# 表形式のフォーマット

# やりたいこと

これを

title1, title2, title3
aaaaaaaaaa, 12332, ccccccc
aaa, 789, ccc
aa, 4541, cccccccccc

こうしたい

+------------+--------+------------+
|   title1| title2|   title3|
+------------+--------+------------+
| aaaaaaaaaa|  12332| ccccccc|
| aaa|    789| ccc|
| aa|   4541| cccccccccc|
+------------+--------+------------+

# 簡易な方法

こうなら、column コマンドでできる。
(Mac版は 出力時の区切り文字は指定できないが、Linuxだと 区切り文字も指定できる)

title1       title2   title3
aaaaaaaaaa   bb       ccccccc
aaa          bbbbb    ccc
cat /tmp/a.txt| column -t -s ,

# 普通にやる場合

tabulate, PrettyTable, texttable, termtable あたりを試せば良いと思う。

# コードで書きたい場合(or外部ライブラリが使えない場合)

こんな簡単に思えることが案外スッキリ書けないもんだす。

#!/usr/bin/env python3

import re

class TableFormatter:
  @classmethod
  def format(cls, headers, rows, delim = '| ', align_auto = True, enclose = True, separate = True, separator_char = '-', separator_delim = '-+-', trim_both_ends = True):
    widths                = [max([len(r[i]) for r in [headers] + rows]) for [i, _] in enumerate(headers)]
    alignfuncs_for_header = [str.center for _ in headers]
    alignfuncs_for_row    = [str.ljust  for _ in headers]

    if align_auto and len(rows) > 0:
      for [i, v] in enumerate(rows[0]):
        if re.match(r'^[+\-]?[0-9,\.]+$', v):
          alignfuncs_for_row[i] = str.rjust
    

    lines = []
    
    lines.append(cls._format_line(headers, widths, delim, alignfuncs_for_header))

    for row in rows:
      lines.append(cls._format_line(row, widths, delim, alignfuncs_for_row))

    if enclose:
      lines = [cls._enclose_line(line, delim) for line in lines]
    
    if trim_both_ends:
      lines = [cls._trim_line(line) for line in lines]

    if separate:
      separators = [separator_char * w for w in widths]
      line = cls._format_line(separators, widths, separator_delim, alignfuncs_for_header)
      if enclose:
        line = cls._enclose_line(line, separator_delim)
      if trim_both_ends:
        line = cls._trim_line(line)

      lines.insert(0, line)
      lines.insert(2, line)
      lines.append(line)

    return '\n'.join(lines)
  
  @classmethod
  def _format_line(cls, values, widths, delim, alignfuncs):
    return delim.join([func(v, w) for [func, v, w] in zip(alignfuncs, values, widths)])

  @classmethod
  def _enclose_line(cls, line, delim):
    return delim + line + delim
  
  @classmethod
  def _trim_line(cls, line, n = 1):
    return line[n:-n]

  @classmethod
  def parse(cls, text = '', delim = r'\s*,\s*'):
    rows = [re.split(delim, line) for line in text.strip().splitlines()]
    headers = rows.pop(0)
    return [headers, rows]


text = '''
title1, title2, title3
aaaaaaaaaa, 12332, ccccccc
aaa, 789, ccc
aa, 4541, cccccccccc
'''

[headers, rows] = TableFormatter.parse(text)

print(TableFormatter.format(headers, rows))

[ 📩 ご意見 ]