创建行为类似于 table 的格式化字符串输出的简单方法

Simple way to create formatted string output that behaves like table

在我去重新发明轮子之前,我想检查一下是否有人已经为此想出了一些办法。

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

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

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

示例

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。所以我想以三列的形式打印所有内容。我 运行 进入问题的地方是列表中倒数第二个字符串项。还有更多类似的例子,因为这是一个有点人为的例子。任何帮助将不胜感激。我以前 运行 遇到过这个问题,所以我想问一下,因为我确定其他人也遇到过这个问题。

想要的结果

Pre-Condition                 Condition                  Output
Button is OFF                 -                          Speed is not on
Button Enabled is OFF         Active is OFF              Speed is on
Button States is HOLD         Button states is           Pedal to the med
                              ACCELERATOR OVERRIDE       here guys
                              AND Set stuff is on 
                               

编辑:使用 list 作为变量,我一直用它搬起石头砸自己的脚

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

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])

旁注

使用 'list' 作为变量是错误的形式。这可能会与内置列表类型发生冲突,应该避免。

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

# 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

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

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)

生产:

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           Pedal to the medal here   
                           ACCELERATOR OVERRIDE       guys                      
                           AND Set stuff is on                                  
                           <Stuff here>

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

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)

这将产生:

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           Pedal to the medal here   
                           ACCELERATOR OVERRIDE       guys                      
                           AND Set stuff is on...                               
One extra value to                                                              
prove the flow  

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