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

时间:2017-06-15 16:52:53

标签: python list format tabular

在我去重新发明轮子之前,我想检查一下有人还没有拿出一些东西。

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

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

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

实施例

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

上面的列表最初是一个三乘五的表。所以我想用三列打印出所有内容。我遇到问题的地方是列表中倒数第二个字符串项。还有更多这样的,因为这是一个有点人为的例子。任何帮助将不胜感激。我之前遇到过这个问题,所以我想问一下,因为我确信其他人也有这个问题。

期望结果

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 
                               

编辑:使用列表作为变量,我一直用脚踩自己的脚

2 个答案:

答案 0 :(得分: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])

旁注

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

答案 1 :(得分:0)

以下是一种非常灵活的方式:

# 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  

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