【问题标题】:Simple way to create formatted string output that behaves like table创建类似于表格的格式化字符串输出的简单方法
【发布时间】:2017-06-15 16:52:53
【问题描述】:

在我重新发明轮子之前,我想检查一下是否有人为此提出了一些建议。

我有一个字符串列表,需要以表格格式打印出来。我从表格中获取数据,这些表格中的某些单元格中可能包含较长的数据字符串。

如果我尝试根据最长的字符串来确定我的列宽,我最终可能会得到巨大的列宽。

我想知道是否已经存在将字符串数据附加到仍然与当前行对齐的另一行的东西(基本上将其视为强制自动填充的单元格)

示例

listObj = ['Pre-Condition:', 'Condition:', 'Output:', 
        'Button is OFF', '-', 'Speed is not on', 
        'Button Enabled is OFF', 'Enabled is ON', 
        'Speed is on', 'Button Active is ON', 'Active is OFF', 
        'Hold steady true north', 'Button States is HOLD', 
        'Button States is ACCELERATOR OVERRIDE AND Set stuff is on <Stuff here>', 
        'Pedal to the medal here guys']

上面的列表最初是一个三乘五的表格。所以我想把所有的东西都打印成三列。我遇到问题的地方是列表中倒数第二个字符串项。这样的例子还有很多,因为这是一个有点做作的例子。任何帮助将不胜感激。我以前遇到过这个问题,所以我想问一下,因为我相信其他人也遇到过这个问题。

期望的结果

前置条件条件输出
按钮关闭 - 速度未开启
按钮 Enabled 为 OFF Active 为 OFF 速度为 on
按钮状态是 HOLD 按钮状态是 Pedal to the med
                              加速器覆盖在这里伙计们
                              和设置的东西是
                               

编辑:使用列表作为变量,我不断地用那个来打自己的脚

【问题讨论】:

  • 嗨,查看python模块“制表”,pypi.python.org/pypi/tabulate
  • 你怎么知道如何对这些字符串进行分组?这只是一个平面列表...
  • 查看我的this answerTextFormatter 类的代码。
  • 原始表格是基于三列格式的,带有前置条件、条件和输出。我添加了想要的结果,这有点类似于原始的格式化表格。
  • 可能值得学习 pandas styling API,它在 jupyter notebooks 中产生非常好的数据帧输出。

标签: python list format tabular


【解决方案1】:

这是对您要查找的内容的硬编码尝试。范围的错误检查也很少。我会让你处理的:)

mylist = ['Pre-Condition:', 'Condition:', 'Output:', 
        'Button is OFF', '-', 'Speed is not on', 
        'Button Enabled is OFF', 'Enabled is ON', 
        'Speed is on', 'Button Active is ON', 'Active is OFF', 
        'Hold steady true north', 'Button States is HOLD', 
        'Button States is ACCELERATOR OVERRIDE AND Set stuff is on <Stuff here>', 
    'Pedal to the medal here guys']

def printCell(row, cellWidth):
    while row != ["","",""]:
        lineformat = ("{:"+str(cellWidth) + "} | ") * 3
        cells=[]
        for n, cell in enumerate(row):
            p = cellWidth
            if len(cell) > cellWidth :
                p = cell[:cellWidth].rfind(" ")
                if p == -1: 
                    p = cellWidth
                row[n] = cell[p:]
            else:
                row[n] = ""
            cells.append(cell[:p])
        print(lineformat.format(*cells))

def printColumns(alist, colCount, colWidth):
    for n in range(0,len(alist)-1,colCount):
        printCell(alist[n:n+colCount], colWidth)
        print("-" * colWidth * colCount)

if __name__ == "__main__":
    printColumns(mylist,3,30)

输出:

Pre-Condition:                 | Condition:                     | Output:                        | 
------------------------------------------------------------------------------------------
Button is OFF                  | -                              | Speed is not on                | 
------------------------------------------------------------------------------------------
Button Enabled is OFF          | Enabled is ON                  | Speed is on                    | 
------------------------------------------------------------------------------------------
Button Active is ON            | Active is OFF                  | Hold steady true north         | 
------------------------------------------------------------------------------------------
Button States is HOLD          | Button States is ACCELERATOR   | Pedal to the medal here guys   | 
                               |  OVERRIDE AND Set stuff is on  |                                | 
                               |  <Stuff here>                  |                                | 
------------------------------------------------------------------------------------------

编辑

为什么不直接创建一个可以用excel直接打开的csv文件呢?

import csv
with open('output.csv', 'w') as f:
    csvOut = csv.writer(f, delimiter=',')
    for n in range(0,len(mylist)-1,3):
        csvOut.writerow(mylist[n:n+3])

旁注

使用“列表”作为变量是不好的形式。这可能与内置列表类型冲突,应该避免。

【讨论】:

  • 这正是我想做的。它实际上最终会被粘贴到 Excel 工作表中的单元格中。但是,我总是可以修改打印语句。
  • Excel 不会为您包装字符串??
  • 是的。我没有在最初的问题中给出整个故事。这些是将上传到数据库的软件要求,excel部分是将它们上传到数据库的中间步骤。在一天结束时,数据最终会显示在某个地方,而现在的方式是,它只会在其中转储一个没有格式的巨大文本球。因此,我尝试对其进行某种格式化,以便测试人员能够真正看到表格格式曾经是什么。
  • 这是我问题范围内的正确答案。我也能够修改它来做我想做的事。至于为什么我没有为此使用 csv 文件。我坚持使用我提供的上传工具,这些工具可以与 excel 一起使用。
  • 您的原始答案适用于大多数数据。但是,在某些情况下,长字符串会导致您的 while 循环进入无限循环。我不确定是什么原因造成的。当我找出导致它的原因时,我将为此编辑我的原始帖子。
【解决方案2】:

这是一种非常灵活的方法:

# a simple function to do our line-splitting per value
def split_value(value, width):
    result = []
    while len(value) > width:  # while our string is longer than allowed
        split_index = value.rfind(" ", 0, width)
        if split_index == -1:  # no space in our current chunk, we must do hard-break
            split_index = width - 1  # set the split to our column width point
        result.append(value[:split_index + 1])  # add the current slice as a sub-row
        value = value[split_index + 1:]  # remove the added slice from our data
    if value:  # there are leftovers from slicing, add them as the last piece
        result.append(value)
    return result

# and our main function...
def draw_table(data, columns, table_width, column_border=1):
    column_data = [data[i::columns] for i in range(columns)]  # split the data into columns
    column_width = table_width // columns - column_border  # max characters per column
    column_template = ("{} " * (columns - 1)) + "{}"  # a simple template for our columns
    empty_value = " " * (column_width + column_border)  # what to print when there's no value
    rows = len(max(column_data, key=len))  # in case we have more data in some of the columns
    for row in range(rows):  # lets print our rows
        row_data = [split_value(x[row], column_width) if len(x) > row else []
                    for x in column_data]  # lets populate our row
        subrows = len(max(row_data, key=len))  # number of subrows for the current row
        for subrow in range(subrows):  # lets go through each of them and print them out
            print(column_template.format(*[x[subrow].ljust(column_width+column_border)
                                           if len(x) > subrow else empty_value
                                           for x in row_data]))  # print our (split) row

这有点曲折,但可以可靠地完成工作,如果您阅读 cmets,这并不难理解。它应该完全符合您的要求(您想要的结果似乎与您列表中的数据不符):

listObj = ['Pre-Condition:', 'Condition:', 'Output:',
           'Button is OFF', '-', 'Speed is not on',
           'Button Enabled is OFF', 'Enabled is ON',
           'Speed is on', 'Button Active is ON', 'Active is OFF',
           'Hold steady true north', 'Button States is HOLD',
           'Button States is ACCELERATOR OVERRIDE AND Set stuff is on <Stuff here>',
           'Pedal to the medal here guys']

# table with three columns, two spaces between columns and of total width of 80 characters
draw_table(listObj, 3, 80, 2)

生产:

前置条件:条件:输出:
按钮关闭 - 速度未开启
按钮 启用为关 启用为开 速度为开
按钮 激活为 ON 激活为 OFF 保持稳定正北
按钮状态是 HOLD 按钮状态是此处的奖牌踏板
                           加速器覆盖伙计们
                           和设置的东西是
                           

作为奖励,它支持不均匀列表,因此您可以执行以下操作:

listObj = ['Pre-Condition:', 'Condition:', 'Output:',
           'Button is OFF', '-', 'Speed is not on',
           'Button Enabled is OFF', 'Enabled is ON',
           'Speed is on', 'Button Active is ON', 'Active is OFF',
           'Hold steady true north', 'Button States is HOLD',
           'Button States is ACCELERATOR OVERRIDE AND Set stuff is on...',
           'Pedal to the medal here guys', "One extra value to prove the flow"]

 draw_table(listObj, 3, 80, 2)

这将产生:

前置条件:条件:输出:
按钮关闭 - 速度未开启
按钮 启用为关 启用为开 速度为开
按钮 激活为 ON 激活为 OFF 保持稳定正北
按钮状态是 HOLD 按钮状态是此处的奖牌踏板
                           加速器覆盖伙计们
                           和设置的东西是...
一个额外的价值
证明流程

像可变列宽这样的未来升级应该不会那么困难,因为行数据拆分是外部的,因此可以添加任何大小。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-08-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多