如何用Python来漂亮地打印ASCII表?

时间:2020-12-26 21:44:01

I'm looking for a Python library for printing tables like this:

我正在寻找一个Python库来打印这样的表:

=======================| column 1 | column 2 |=======================| value1   | value2   || value3   | value4   |=======================

I've found asciitable but it doesn't do the borders etc. I don't need any complex formatting of data items, they're just strings. I do need it to auto-size columns.

我发现了一个可编程的,但它不做边界等等,我不需要任何复杂的数据格式,它们只是字符串。我确实需要它自动大小的列。

Does such a thing exist, or do I need to spend a few minutes writing my own?

这样的事情存在吗?还是我需要花几分钟写我自己的?

13 个解决方案

#1


35  

Here's a quick and dirty little function I wrote for displaying the results from SQL queries I can only make over a SOAP API. It expects an input of a sequence of one or more namedtuples as table rows. If there's only one record, it prints it out differently.

下面是我为显示SQL查询的结果而编写的一个快速而肮脏的小函数,我只能通过SOAP API进行查询。它期望一个或多个命名元组的序列的输入作为表行。如果只有一条记录,它会以不同的方式打印出来。

It is handy for me and could be a starting point for you:

这对我来说很方便,也可以作为你的起点:

def pprinttable(rows):  if len(rows) > 1:    headers = rows[0]._fields    lens = []    for i in range(len(rows[0])):      lens.append(len(max([x[i] for x in rows] + [headers[i]],key=lambda x:len(str(x)))))    formats = []    hformats = []    for i in range(len(rows[0])):      if isinstance(rows[0][i], int):        formats.append("%%%dd" % lens[i])      else:        formats.append("%%-%ds" % lens[i])      hformats.append("%%-%ds" % lens[i])    pattern = " | ".join(formats)    hpattern = " | ".join(hformats)    separator = "-+-".join(['-' * n for n in lens])    print hpattern % tuple(headers)    print separator    _u = lambda t: t.decode('UTF-8', 'replace') if isinstance(t, str) else t    for line in rows:        print pattern % tuple(_u(t) for t in line)  elif len(rows) == 1:    row = rows[0]    hwidth = len(max(row._fields,key=lambda x: len(x)))    for i in range(len(row)):      print "%*s = %s" % (hwidth,row._fields[i],row[i])

Sample output:

样例输出:

pkid                                 | fkn                                  | npi-------------------------------------+--------------------------------------+----405fd665-0a2f-4f69-7320-be01201752ec | 8c9949b9-552e-e448-64e2-74292834c73e | 05b517507-2a42-ad2e-98dc-8c9ac6152afa | f972bee7-f5a4-8532-c4e5-2e82897b10f6 | 02f960dfc-b67a-26be-d1b3-9b105535e0a8 | ec3e1058-8840-c9f2-3b25-2488f8b3a8af | 1c71b28a3-5299-7f4d-f27a-7ad8aeadafe0 | 72d25703-4735-310b-2e06-ff76af1e45ed | 03b0a5021-a52b-9ba0-1439-d5aafcf348e7 | d81bb78a-d984-e957-034d-87434acb4e97 | 196c36bb7-c4f4-2787-ada8-4aadc17d1123 | c171fe85-33e2-6481-0791-2922267e8777 | 195d0f85f-71da-bb9a-2d80-fe27f7c02fe2 | 226f964c-028d-d6de-bf6c-688d2908c5ae | 1132aa774-42e5-3d3f-498b-50b44a89d401 | 44e31f89-d089-8afc-f4b1-ada051c01474 | 1ff91641a-5802-be02-bece-79bca993fdbc | 33d8294a-053d-6ab4-94d4-890b47fcf70d | 1f3196e15-5b61-e92d-e717-f00ed93fe8ae | 62fa4566-5ca2-4a36-f872-4d00f7abadcf | 1

Example

例子

>>> from collections import namedtuple>>> Row = namedtuple('Row',['first','second','third'])>>> data = Row(1,2,3)>>> dataRow(first=1, second=2, third=3)>>> pprinttable([data]) first = 1second = 2 third = 3>>> pprinttable([data,data])first | second | third------+--------+------    1 |      2 |     3    1 |      2 |     3

#2


31  

I've read this question long time ago, and finished writing my own pretty-printer for tables: tabulate.

我很久以前就读过这个问题了,我已经写好了我自己的表格用的漂亮打印机:表格。

My use case is:

我的用例是:

  • I want a one-liner most of the time
  • 我大多数时候都想要一句俏皮话
  • which is smart enough to figure the best formatting for me
  • 哪一个足够聪明,可以为我找到最好的格式?
  • and can output different plain-text formats
  • 并且可以输出不同的明文格式

Given your example, grid is probably the most similar output format:

例如,grid可能是最类似的输出格式:

from tabulate import tabulateprint tabulate([["value1", "value2"], ["value3", "value4"]], ["column 1", "column 2"], tablefmt="grid")+------------+------------+| column 1   | column 2   |+============+============+| value1     | value2     |+------------+------------+| value3     | value4     |+------------+------------+

Other supported formats are plain (no lines), simple (Pandoc simple tables), pipe (like tables in PHP Markdown Extra), orgtbl (like tables in Emacs' org-mode), rst (like simple tables in reStructuredText). grid and orgtbl are easily editable in Emacs.

其他受支持的格式有plain(无行)、simple (Pandoc简单表)、pipe(类似于PHP Markdown Extra中的表)、orgtbl(类似于Emacs的org-mode中的表)、rst(类似于structuredtext中的简单表)。在Emacs中,网格和orgtbl很容易编辑。

Performance-wise, tabulate is slightly slower than asciitable, but much faster than PrettyTable and texttable.

在性能方面,表格比可测试的稍慢,但比美观的和可编辑的快得多。

P.S. I'm also a big fan of aligning numbers by a decimal column. So this is the default alignment for numbers if there are any (overridable).

另外,我也很喜欢用十进制来排列数字。如果有的话,这是数字的默认对齐方式。

#3


17  

okay old thread,, but the best I've found for this is Prettytable... are there better?

好,老线程,但我发现的最好的是漂亮的……有更好的吗?

#4


17  

For some reason when I included 'docutils' in my google searches I stumbled across texttable, which seems to be what I'm looking for.

出于某种原因,当我在谷歌搜索中加入“docutils”时,我偶然发现了texttable,这似乎正是我要找的。

#5


10  

I too wrote my own solution to this. I tried to keep it simple.

我也写了我自己的解决方法。我尽量保持简单。

https://github.com/Robpol86/terminaltables

https://github.com/Robpol86/terminaltables

from terminaltables import AsciiTabletable_data = [    ['Heading1', 'Heading2'],    ['row1 column1', 'row1 column2'],    ['row2 column1', 'row2 column2']]table = AsciiTable(table_data)print table.table+--------------+--------------+| Heading1     | Heading2     |+--------------+--------------+| row1 column1 | row1 column2 || row2 column1 | row2 column2 |+--------------+--------------+table.inner_heading_row_border = Falseprint table.table+--------------+--------------+| Heading1     | Heading2     || row1 column1 | row1 column2 || row2 column1 | row2 column2 |+--------------+--------------+table.inner_row_border = Truetable.justify_columns[1] = 'right'table.table_data[1][1] += '\nnewline'print table.table+--------------+--------------+| Heading1     |     Heading2 |+--------------+--------------+| row1 column1 | row1 column2 ||              |      newline |+--------------+--------------+| row2 column1 | row2 column2 |+--------------+--------------+

#6


4  

Version using w3m designed to handle the types MattH's version accepts:

使用w3m设计处理MattH版本的类型的版本接受:

import subprocessimport tempfileimport htmldef pprinttable(rows):    esc = lambda x: html.escape(str(x))    sour = "<table border=1>"    if len(rows) == 1:        for i in range(len(rows[0]._fields)):            sour += "<tr><th>%s<td>%s" % (esc(rows[0]._fields[i]), esc(rows[0][i]))    else:        sour += "<tr>" + "".join(["<th>%s" % esc(x) for x in rows[0]._fields])        sour += "".join(["<tr>%s" % "".join(["<td>%s" % esc(y) for y in x]) for x in rows])    with tempfile.NamedTemporaryFile(suffix=".html") as f:        f.write(sour.encode("utf-8"))        f.flush()        print(            subprocess            .Popen(["w3m","-dump",f.name], stdout=subprocess.PIPE)            .communicate()[0].decode("utf-8").strip()        )from collections import namedtupleRow = namedtuple('Row',['first','second','third'])data1 = Row(1,2,3)data2 = Row(4,5,6)pprinttable([data1])pprinttable([data1,data2])

results in:

结果:

┌───────┬─┐│ first │1│├───────┼─┤│second │2│├───────┼─┤│ third │3│└───────┴─┘┌─────┬───────┬─────┐│first│second │third│├─────┼───────┼─────┤│1    │2      │3    │├─────┼───────┼─────┤│4    │5      │6    │└─────┴───────┴─────┘

#7


3  

If you want a table with column and row spans, then try my library dashtable

如果您想要一个具有列和行跨度的表,那么请尝试我的库指示表

from dashtable import data2rsttable = [        ["Header 1", "Header 2", "Header3", "Header 4"],        ["row 1", "column 2", "column 3", "column 4"],        ["row 2", "Cells span columns.", "", ""],        ["row 3", "Cells\nspan rows.", "- Cells\n- contain\n- blocks", ""],        ["row 4", "", "", ""]    ]# [Row, Column] pairs of merged cellsspan0 = ([2, 1], [2, 2], [2, 3])span1 = ([3, 1], [4, 1])span2 = ([3, 3], [3, 2], [4, 2], [4, 3])my_spans = [span0, span1, span2]print(data2rst(table, spans=my_spans, use_headers=True))

Which outputs:

输出:

+----------+------------+----------+----------+| Header 1 | Header 2   | Header3  | Header 4 |+==========+============+==========+==========+| row 1    | column 2   | column 3 | column 4 |+----------+------------+----------+----------+| row 2    | Cells span columns.              |+----------+----------------------------------+| row 3    | Cells      | - Cells             |+----------+ span rows. | - contain           || row 4    |            | - blocks            |+----------+------------+---------------------+

#8


2  

I know it the question is a bit old but here's my attempt at this:

我知道这个问题有点过时,但我的尝试是:

https://gist.github.com/lonetwin/4721748

https://gist.github.com/lonetwin/4721748

It is a bit more readable IMHO (although it doesn't differentiate between single / multiple rows like @MattH's solutions does, nor does it use NamedTuples).

它更具可读性(尽管它不像@MattH的解决方案那样区分单行/多行,也不使用NamedTuples)。

#9


2  

I use this small utility function.

我用这个小效用函数。

def get_pretty_table(iterable, header):    max_len = [len(x) for x in header]    for row in iterable:        row = [row] if type(row) not in (list, tuple) else row        for index, col in enumerate(row):            if max_len[index] < len(str(col)):                max_len[index] = len(str(col))    output = '-' * (sum(max_len) + 1) + '\n'    output += '|' + ''.join([h + ' ' * (l - len(h)) + '|' for h, l in zip(header, max_len)]) + '\n'    output += '-' * (sum(max_len) + 1) + '\n'    for row in iterable:        row = [row] if type(row) not in (list, tuple) else row        output += '|' + ''.join([str(c) + ' ' * (l - len(str(c))) + '|' for c, l in zip(row, max_len)]) + '\n'    output += '-' * (sum(max_len) + 1) + '\n'    return outputprint get_pretty_table([[1, 2], [3, 4]], ['header 1', 'header 2'])

output

输出

-----------------|header 1|header 2|-----------------|1       |2       ||3       |4       |-----------------

#10


1  

You can try BeautifulTable. It does what you want to do. Here's an example from it's documentation

你可以试试BeautifulTable。它做你想做的事。这是它的文档中的一个例子

>>> from beautifultable import BeautifulTable>>> table = BeautifulTable()>>> table.column_headers = ["name", "rank", "gender"]>>> table.append_row(["Jacob", 1, "boy"])>>> table.append_row(["Isabella", 1, "girl"])>>> table.append_row(["Ethan", 2, "boy"])>>> table.append_row(["Sophia", 2, "girl"])>>> table.append_row(["Michael", 3, "boy"])>>> print(table)+----------+------+--------+|   name   | rank | gender |+----------+------+--------+|  Jacob   |  1   |  boy   |+----------+------+--------+| Isabella |  1   |  girl  |+----------+------+--------+|  Ethan   |  2   |  boy   |+----------+------+--------+|  Sophia  |  2   |  girl  |+----------+------+--------+| Michael  |  3   |  boy   |+----------+------+--------+

#11


0  

Here's my solution:

这是我的解决方案:

def make_table(columns, data):    """Create an ASCII table and return it as a string.    Pass a list of strings to use as columns in the table and a list of    dicts. The strings in 'columns' will be used as the keys to the dicts in    'data.'    Not all column values have to be present in each data dict.    >>> print(make_table(["a", "b"], [{"a": "1", "b": "test"}]))    | a | b    |    |----------|    | 1 | test |    """    # Calculate how wide each cell needs to be    cell_widths = {}    for c in columns:        values = [str(d.get(c, "")) for d in data]        cell_widths[c] = len(max(values + [c]))    # Used for formatting rows of data    row_template = "|" + " {} |" * len(columns)    # CONSTRUCT THE TABLE    # The top row with the column titles    justified_column_heads = [c.ljust(cell_widths[c]) for c in columns]    header = row_template.format(*justified_column_heads)    # The second row contains separators    sep = "|" + "-" * (len(header) - 2) + "|"    # Rows of data    rows = []    for d in data:        fields = [str(d.get(c, "")).ljust(cell_widths[c]) for c in columns]        row = row_template.format(*fields)        rows.append(row)    return "\n".join([header, sep] + rows)

#12


0  

This can be done with only builtin modules fairly compactly using list and string comprehensions. Accepts a list of dictionaries all of the same format...

这可以通过使用列表和字符串理解来实现。接受所有相同格式的字典列表……

def tableit(dictlist):    lengths = [ max(map(lambda x:len(x.get(k)), dictlist) + [len(k)]) for k in dictlist[0].keys() ]    lenstr = " | ".join("{:<%s}" % m for m in lengths)    lenstr += "\n"    outmsg = lenstr.format(*dictlist[0].keys())    outmsg += "-" * (sum(lengths) + 3*len(lengths))    outmsg += "\n"    outmsg += "".join(        lenstr.format(*v) for v in [ item.values() for item in dictlist ]    )    return outmsg

#13


0  

from sys import stderr, stdout    def create_table(table: dict, full_row: bool = False) -> None:        min_len = len(min((v for v in table.values()), key=lambda q: len(q)))        max_len = len(max((v for v in table.values()), key=lambda q: len(q)))        if min_len < max_len:            stderr.write("Table is out of shape, please make sure all columns have the same length.")            stderr.flush()            return        additional_spacing = 1        heading_separator = '| '        horizontal_split = '| '        rc_separator = ''        key_list = list(table.keys())        rc_len_values = []        for key in key_list:            rc_len = len(max((v for v in table[key]), key=lambda q: len(str(q))))            rc_len_values += ([rc_len, [key]] for n in range(len(table[key])))            heading_line = (key + (" " * (rc_len + (additional_spacing + 1)))) + heading_separator            stdout.write(heading_line)            rc_separator += ("-" * (len(key) + (rc_len + (additional_spacing + 1)))) + '+-'            if key is key_list[-1]:                stdout.flush()                stdout.write('\n' + rc_separator + '\n')        value_list = [v for vl in table.values() for v in vl]        aligned_data_offset = max_len        row_count = len(key_list)        next_idx = 0        newline_indicator = 0        iterations = 0        for n in range(len(value_list)):            key = rc_len_values[next_idx][1][0]            rc_len = rc_len_values[next_idx][0]            line = ('{:{}} ' + " " * len(key)).format(value_list[next_idx], str(rc_len + additional_spacing)) + horizontal_split            if next_idx >= (len(value_list) - aligned_data_offset):                next_idx = iterations + 1                iterations += 1            else:                next_idx += aligned_data_offset            if newline_indicator >= row_count:                if full_row:                    stdout.flush()                    stdout.write('\n' + rc_separator + '\n')                else:                    stdout.flush()                    stdout.write('\n')                newline_indicator = 0            stdout.write(line)            newline_indicator += 1        stdout.write('\n' + rc_separator + '\n')        stdout.flush()

Example:

例子:

table = {        "uid": ["0", "1", "2", "3"],        "name": ["Jon", "Doe", "Lemma", "Hemma"]    }create_table(table)

Output:

输出:

uid   | name       | ------+------------+-0     | Jon        | 1     | Doe        | 2     | Lemma      | 3     | Hemma      | ------+------------+-

#1


35  

Here's a quick and dirty little function I wrote for displaying the results from SQL queries I can only make over a SOAP API. It expects an input of a sequence of one or more namedtuples as table rows. If there's only one record, it prints it out differently.

下面是我为显示SQL查询的结果而编写的一个快速而肮脏的小函数,我只能通过SOAP API进行查询。它期望一个或多个命名元组的序列的输入作为表行。如果只有一条记录,它会以不同的方式打印出来。

It is handy for me and could be a starting point for you:

这对我来说很方便,也可以作为你的起点:

def pprinttable(rows):  if len(rows) > 1:    headers = rows[0]._fields    lens = []    for i in range(len(rows[0])):      lens.append(len(max([x[i] for x in rows] + [headers[i]],key=lambda x:len(str(x)))))    formats = []    hformats = []    for i in range(len(rows[0])):      if isinstance(rows[0][i], int):        formats.append("%%%dd" % lens[i])      else:        formats.append("%%-%ds" % lens[i])      hformats.append("%%-%ds" % lens[i])    pattern = " | ".join(formats)    hpattern = " | ".join(hformats)    separator = "-+-".join(['-' * n for n in lens])    print hpattern % tuple(headers)    print separator    _u = lambda t: t.decode('UTF-8', 'replace') if isinstance(t, str) else t    for line in rows:        print pattern % tuple(_u(t) for t in line)  elif len(rows) == 1:    row = rows[0]    hwidth = len(max(row._fields,key=lambda x: len(x)))    for i in range(len(row)):      print "%*s = %s" % (hwidth,row._fields[i],row[i])

Sample output:

样例输出:

pkid                                 | fkn                                  | npi-------------------------------------+--------------------------------------+----405fd665-0a2f-4f69-7320-be01201752ec | 8c9949b9-552e-e448-64e2-74292834c73e | 05b517507-2a42-ad2e-98dc-8c9ac6152afa | f972bee7-f5a4-8532-c4e5-2e82897b10f6 | 02f960dfc-b67a-26be-d1b3-9b105535e0a8 | ec3e1058-8840-c9f2-3b25-2488f8b3a8af | 1c71b28a3-5299-7f4d-f27a-7ad8aeadafe0 | 72d25703-4735-310b-2e06-ff76af1e45ed | 03b0a5021-a52b-9ba0-1439-d5aafcf348e7 | d81bb78a-d984-e957-034d-87434acb4e97 | 196c36bb7-c4f4-2787-ada8-4aadc17d1123 | c171fe85-33e2-6481-0791-2922267e8777 | 195d0f85f-71da-bb9a-2d80-fe27f7c02fe2 | 226f964c-028d-d6de-bf6c-688d2908c5ae | 1132aa774-42e5-3d3f-498b-50b44a89d401 | 44e31f89-d089-8afc-f4b1-ada051c01474 | 1ff91641a-5802-be02-bece-79bca993fdbc | 33d8294a-053d-6ab4-94d4-890b47fcf70d | 1f3196e15-5b61-e92d-e717-f00ed93fe8ae | 62fa4566-5ca2-4a36-f872-4d00f7abadcf | 1

Example

例子

>>> from collections import namedtuple>>> Row = namedtuple('Row',['first','second','third'])>>> data = Row(1,2,3)>>> dataRow(first=1, second=2, third=3)>>> pprinttable([data]) first = 1second = 2 third = 3>>> pprinttable([data,data])first | second | third------+--------+------    1 |      2 |     3    1 |      2 |     3

#2


31  

I've read this question long time ago, and finished writing my own pretty-printer for tables: tabulate.

我很久以前就读过这个问题了,我已经写好了我自己的表格用的漂亮打印机:表格。

My use case is:

我的用例是:

  • I want a one-liner most of the time
  • 我大多数时候都想要一句俏皮话
  • which is smart enough to figure the best formatting for me
  • 哪一个足够聪明,可以为我找到最好的格式?
  • and can output different plain-text formats
  • 并且可以输出不同的明文格式

Given your example, grid is probably the most similar output format:

例如,grid可能是最类似的输出格式:

from tabulate import tabulateprint tabulate([["value1", "value2"], ["value3", "value4"]], ["column 1", "column 2"], tablefmt="grid")+------------+------------+| column 1   | column 2   |+============+============+| value1     | value2     |+------------+------------+| value3     | value4     |+------------+------------+

Other supported formats are plain (no lines), simple (Pandoc simple tables), pipe (like tables in PHP Markdown Extra), orgtbl (like tables in Emacs' org-mode), rst (like simple tables in reStructuredText). grid and orgtbl are easily editable in Emacs.

其他受支持的格式有plain(无行)、simple (Pandoc简单表)、pipe(类似于PHP Markdown Extra中的表)、orgtbl(类似于Emacs的org-mode中的表)、rst(类似于structuredtext中的简单表)。在Emacs中,网格和orgtbl很容易编辑。

Performance-wise, tabulate is slightly slower than asciitable, but much faster than PrettyTable and texttable.

在性能方面,表格比可测试的稍慢,但比美观的和可编辑的快得多。

P.S. I'm also a big fan of aligning numbers by a decimal column. So this is the default alignment for numbers if there are any (overridable).

另外,我也很喜欢用十进制来排列数字。如果有的话,这是数字的默认对齐方式。

#3


17  

okay old thread,, but the best I've found for this is Prettytable... are there better?

好,老线程,但我发现的最好的是漂亮的……有更好的吗?

#4


17  

For some reason when I included 'docutils' in my google searches I stumbled across texttable, which seems to be what I'm looking for.

出于某种原因,当我在谷歌搜索中加入“docutils”时,我偶然发现了texttable,这似乎正是我要找的。

#5


10  

I too wrote my own solution to this. I tried to keep it simple.

我也写了我自己的解决方法。我尽量保持简单。

https://github.com/Robpol86/terminaltables

https://github.com/Robpol86/terminaltables

from terminaltables import AsciiTabletable_data = [    ['Heading1', 'Heading2'],    ['row1 column1', 'row1 column2'],    ['row2 column1', 'row2 column2']]table = AsciiTable(table_data)print table.table+--------------+--------------+| Heading1     | Heading2     |+--------------+--------------+| row1 column1 | row1 column2 || row2 column1 | row2 column2 |+--------------+--------------+table.inner_heading_row_border = Falseprint table.table+--------------+--------------+| Heading1     | Heading2     || row1 column1 | row1 column2 || row2 column1 | row2 column2 |+--------------+--------------+table.inner_row_border = Truetable.justify_columns[1] = 'right'table.table_data[1][1] += '\nnewline'print table.table+--------------+--------------+| Heading1     |     Heading2 |+--------------+--------------+| row1 column1 | row1 column2 ||              |      newline |+--------------+--------------+| row2 column1 | row2 column2 |+--------------+--------------+

#6


4  

Version using w3m designed to handle the types MattH's version accepts:

使用w3m设计处理MattH版本的类型的版本接受:

import subprocessimport tempfileimport htmldef pprinttable(rows):    esc = lambda x: html.escape(str(x))    sour = "<table border=1>"    if len(rows) == 1:        for i in range(len(rows[0]._fields)):            sour += "<tr><th>%s<td>%s" % (esc(rows[0]._fields[i]), esc(rows[0][i]))    else:        sour += "<tr>" + "".join(["<th>%s" % esc(x) for x in rows[0]._fields])        sour += "".join(["<tr>%s" % "".join(["<td>%s" % esc(y) for y in x]) for x in rows])    with tempfile.NamedTemporaryFile(suffix=".html") as f:        f.write(sour.encode("utf-8"))        f.flush()        print(            subprocess            .Popen(["w3m","-dump",f.name], stdout=subprocess.PIPE)            .communicate()[0].decode("utf-8").strip()        )from collections import namedtupleRow = namedtuple('Row',['first','second','third'])data1 = Row(1,2,3)data2 = Row(4,5,6)pprinttable([data1])pprinttable([data1,data2])

results in:

结果:

┌───────┬─┐│ first │1│├───────┼─┤│second │2│├───────┼─┤│ third │3│└───────┴─┘┌─────┬───────┬─────┐│first│second │third│├─────┼───────┼─────┤│1    │2      │3    │├─────┼───────┼─────┤│4    │5      │6    │└─────┴───────┴─────┘

#7


3  

If you want a table with column and row spans, then try my library dashtable

如果您想要一个具有列和行跨度的表,那么请尝试我的库指示表

from dashtable import data2rsttable = [        ["Header 1", "Header 2", "Header3", "Header 4"],        ["row 1", "column 2", "column 3", "column 4"],        ["row 2", "Cells span columns.", "", ""],        ["row 3", "Cells\nspan rows.", "- Cells\n- contain\n- blocks", ""],        ["row 4", "", "", ""]    ]# [Row, Column] pairs of merged cellsspan0 = ([2, 1], [2, 2], [2, 3])span1 = ([3, 1], [4, 1])span2 = ([3, 3], [3, 2], [4, 2], [4, 3])my_spans = [span0, span1, span2]print(data2rst(table, spans=my_spans, use_headers=True))

Which outputs:

输出:

+----------+------------+----------+----------+| Header 1 | Header 2   | Header3  | Header 4 |+==========+============+==========+==========+| row 1    | column 2   | column 3 | column 4 |+----------+------------+----------+----------+| row 2    | Cells span columns.              |+----------+----------------------------------+| row 3    | Cells      | - Cells             |+----------+ span rows. | - contain           || row 4    |            | - blocks            |+----------+------------+---------------------+

#8


2  

I know it the question is a bit old but here's my attempt at this:

我知道这个问题有点过时,但我的尝试是:

https://gist.github.com/lonetwin/4721748

https://gist.github.com/lonetwin/4721748

It is a bit more readable IMHO (although it doesn't differentiate between single / multiple rows like @MattH's solutions does, nor does it use NamedTuples).

它更具可读性(尽管它不像@MattH的解决方案那样区分单行/多行,也不使用NamedTuples)。

#9


2  

I use this small utility function.

我用这个小效用函数。

def get_pretty_table(iterable, header):    max_len = [len(x) for x in header]    for row in iterable:        row = [row] if type(row) not in (list, tuple) else row        for index, col in enumerate(row):            if max_len[index] < len(str(col)):                max_len[index] = len(str(col))    output = '-' * (sum(max_len) + 1) + '\n'    output += '|' + ''.join([h + ' ' * (l - len(h)) + '|' for h, l in zip(header, max_len)]) + '\n'    output += '-' * (sum(max_len) + 1) + '\n'    for row in iterable:        row = [row] if type(row) not in (list, tuple) else row        output += '|' + ''.join([str(c) + ' ' * (l - len(str(c))) + '|' for c, l in zip(row, max_len)]) + '\n'    output += '-' * (sum(max_len) + 1) + '\n'    return outputprint get_pretty_table([[1, 2], [3, 4]], ['header 1', 'header 2'])

output

输出

-----------------|header 1|header 2|-----------------|1       |2       ||3       |4       |-----------------

#10


1  

You can try BeautifulTable. It does what you want to do. Here's an example from it's documentation

你可以试试BeautifulTable。它做你想做的事。这是它的文档中的一个例子

>>> from beautifultable import BeautifulTable>>> table = BeautifulTable()>>> table.column_headers = ["name", "rank", "gender"]>>> table.append_row(["Jacob", 1, "boy"])>>> table.append_row(["Isabella", 1, "girl"])>>> table.append_row(["Ethan", 2, "boy"])>>> table.append_row(["Sophia", 2, "girl"])>>> table.append_row(["Michael", 3, "boy"])>>> print(table)+----------+------+--------+|   name   | rank | gender |+----------+------+--------+|  Jacob   |  1   |  boy   |+----------+------+--------+| Isabella |  1   |  girl  |+----------+------+--------+|  Ethan   |  2   |  boy   |+----------+------+--------+|  Sophia  |  2   |  girl  |+----------+------+--------+| Michael  |  3   |  boy   |+----------+------+--------+

#11


0  

Here's my solution:

这是我的解决方案:

def make_table(columns, data):    """Create an ASCII table and return it as a string.    Pass a list of strings to use as columns in the table and a list of    dicts. The strings in 'columns' will be used as the keys to the dicts in    'data.'    Not all column values have to be present in each data dict.    >>> print(make_table(["a", "b"], [{"a": "1", "b": "test"}]))    | a | b    |    |----------|    | 1 | test |    """    # Calculate how wide each cell needs to be    cell_widths = {}    for c in columns:        values = [str(d.get(c, "")) for d in data]        cell_widths[c] = len(max(values + [c]))    # Used for formatting rows of data    row_template = "|" + " {} |" * len(columns)    # CONSTRUCT THE TABLE    # The top row with the column titles    justified_column_heads = [c.ljust(cell_widths[c]) for c in columns]    header = row_template.format(*justified_column_heads)    # The second row contains separators    sep = "|" + "-" * (len(header) - 2) + "|"    # Rows of data    rows = []    for d in data:        fields = [str(d.get(c, "")).ljust(cell_widths[c]) for c in columns]        row = row_template.format(*fields)        rows.append(row)    return "\n".join([header, sep] + rows)

#12


0  

This can be done with only builtin modules fairly compactly using list and string comprehensions. Accepts a list of dictionaries all of the same format...

这可以通过使用列表和字符串理解来实现。接受所有相同格式的字典列表……

def tableit(dictlist):    lengths = [ max(map(lambda x:len(x.get(k)), dictlist) + [len(k)]) for k in dictlist[0].keys() ]    lenstr = " | ".join("{:<%s}" % m for m in lengths)    lenstr += "\n"    outmsg = lenstr.format(*dictlist[0].keys())    outmsg += "-" * (sum(lengths) + 3*len(lengths))    outmsg += "\n"    outmsg += "".join(        lenstr.format(*v) for v in [ item.values() for item in dictlist ]    )    return outmsg

#13


0  

from sys import stderr, stdout    def create_table(table: dict, full_row: bool = False) -> None:        min_len = len(min((v for v in table.values()), key=lambda q: len(q)))        max_len = len(max((v for v in table.values()), key=lambda q: len(q)))        if min_len < max_len:            stderr.write("Table is out of shape, please make sure all columns have the same length.")            stderr.flush()            return        additional_spacing = 1        heading_separator = '| '        horizontal_split = '| '        rc_separator = ''        key_list = list(table.keys())        rc_len_values = []        for key in key_list:            rc_len = len(max((v for v in table[key]), key=lambda q: len(str(q))))            rc_len_values += ([rc_len, [key]] for n in range(len(table[key])))            heading_line = (key + (" " * (rc_len + (additional_spacing + 1)))) + heading_separator            stdout.write(heading_line)            rc_separator += ("-" * (len(key) + (rc_len + (additional_spacing + 1)))) + '+-'            if key is key_list[-1]:                stdout.flush()                stdout.write('\n' + rc_separator + '\n')        value_list = [v for vl in table.values() for v in vl]        aligned_data_offset = max_len        row_count = len(key_list)        next_idx = 0        newline_indicator = 0        iterations = 0        for n in range(len(value_list)):            key = rc_len_values[next_idx][1][0]            rc_len = rc_len_values[next_idx][0]            line = ('{:{}} ' + " " * len(key)).format(value_list[next_idx], str(rc_len + additional_spacing)) + horizontal_split            if next_idx >= (len(value_list) - aligned_data_offset):                next_idx = iterations + 1                iterations += 1            else:                next_idx += aligned_data_offset            if newline_indicator >= row_count:                if full_row:                    stdout.flush()                    stdout.write('\n' + rc_separator + '\n')                else:                    stdout.flush()                    stdout.write('\n')                newline_indicator = 0            stdout.write(line)            newline_indicator += 1        stdout.write('\n' + rc_separator + '\n')        stdout.flush()

Example:

例子:

table = {        "uid": ["0", "1", "2", "3"],        "name": ["Jon", "Doe", "Lemma", "Hemma"]    }create_table(table)

Output:

输出:

uid   | name       | ------+------------+-0     | Jon        | 1     | Doe        | 2     | Lemma      | 3     | Hemma      | ------+------------+-