【问题标题】:Convert Python Pretty table to CSV using shell or batch command line使用 shell 或批处理命令行将 Python Pretty 表转换为 CSV
【发布时间】:2015-11-14 16:26:00
【问题描述】:

有什么简单的方法可以将 Python Pretty 表格的输出转换为语法上可用的格式,例如 CSV。

输出如下所示:

C:\test> 新星列表

    spu+--------------------------------------+--------+--------+------------+-------------+-----------------------------------+
     | ID                                   | Name   | Status | Task State | Power State | Networks                          |
     +--------------------------------------+--------+--------+------------+-------------+-----------------------------------+
     | 6bca09f8-a320-44d4-a11f-647dcec0aaa1 | tester | ACTIVE | -          |  Running     | OpenStack-net=10.0.0.1, 10.0.0.3 |
     +--------------------------------------+--------+--------+------------+-------------+-----------------------------------+

【问题讨论】:

标签: python csv prettytable


【解决方案1】:

@AdamSmith 的答案有一个很好的方法来解析原始表字符串。这里有一些添加将它变成一个通用函数(我选择不使用csv 模块所以没有额外的依赖)

def ptable_to_csv(table, filename, headers=True):
    """Save PrettyTable results to a CSV file.

    Adapted from @AdamSmith https://stackoverflow.com/questions/32128226

    :param PrettyTable table: Table object to get data from.
    :param str filename: Filepath for the output CSV.
    :param bool headers: Whether to include the header row in the CSV.
    :return: None
    """
    raw = table.get_string()
    data = [tuple(filter(None, map(str.strip, splitline)))
            for line in raw.splitlines()
            for splitline in [line.split('|')] if len(splitline) > 1]
    if table.title is not None:
        data = data[1:]
    if not headers:
        data = data[1:]
    with open(filename, 'w') as f:
        for d in data:
            f.write('{}\n'.format(','.join(d)))

【讨论】:

  • @DhairyTripathi 难道是因为len(data) == 0
【解决方案2】:

这是一个使用正则表达式的解决方案。它也适用于任意数量的列(列数通过计算第一行中加号的数量来确定)。

input_string = """spu+--------------------------------------+--------+--------+------------+-------------+-----------------------------------+
     | ID                                   | Name   | Status | Task State | Power State | Networks                          |
     +--------------------------------------+--------+--------+------------+-------------+-----------------------------------+
     | 6bca09f8-a320-44d4-a11f-647dcec0aaa1 | tester | ACTIVE | -          |  Running     | OpenStack-net=10.0.0.1, 10.0.0.3 |
     +--------------------------------------+--------+--------+------------+-------------+-----------------------------------+"""

import re, csv, sys
def pretty_table_to_tuples(input_str):
    lines = input_str.split("\n")
    num_columns = len(re.findall("\+", lines[0])) - 1
    line_regex = r"\|" + (r" +(.*?) +\|"*num_columns)
    for line in lines:
        m = re.match(line_regex, line.strip())
        if m:
            yield m.groups()

w = csv.writer(sys.stdout)
w.writerows(pretty_table_to_tuples(input_string))

【讨论】:

    【解决方案3】:

    这是一个真正丑陋的单线

    import csv
    
    s = """\
      spu+--------------------------------------+--------+--------+------------+-------------+-----------------------------------+
         | ID                                   | Name   | Status | Task State | Power State | Networks                          |
         +--------------------------------------+--------+--------+------------+-------------+-----------------------------------+
         | 6bca09f8-a320-44d4-a11f-647dcec0aaa1 | tester | ACTIVE | -          |  Running     | OpenStack-net=10.0.0.1, 10.0.0.3 |
         +--------------------------------------+--------+--------+------------+-------------+-----------------------------------+"""
    
    result = [tuple(filter(None, map(str.strip, splitline))) for line in s.splitlines() for splitline in [line.split("|")] if len(splitline) > 1]
    
    with open('output.csv', 'wb') as outcsv:
        writer = csv.writer(outcsv)
        writer.writerows(result)
    

    我可以把它拆开一点让它更好看:

    splitlines = s.splitlines()
    splitdata = line.split("|")
    splitdata = filter(lambda line: len(line) > 1, data)
    # toss the lines that don't have any data in them -- pure separator lines
    header, *data = [[field.strip() for field in line if field.strip()] for line in splitdata]
    
    result = [header] + data
    # I'm really just separating these, then re-joining them, but sometimes having
    # the headers separately is an important thing!
    

    或者可能更有帮助:

    result = []
    
    for line in s.splitlines():
        splitdata = line.split("|")
        if len(splitdata) == 1:
            continue  # skip lines with no separators
        linedata = []
        for field in splitdata:
            field = field.strip()
            if field:
                linedata.append(field)
        result.append(linedata)
    

    【讨论】:

      【解决方案4】:

      也许这会让你接近:

      nova list | grep -v '\-\-\-\-' | sed 's/^[^|]\+|//g' | sed 's/|\(.\)/,\1/g' | tr '|' '\n'
      

      这将去除 --- 行 删除前导 | 替换除最后一个 |和 , 替换最后一个 |与\n

      【讨论】:

      • 感谢您的调查,但我认为应该在某处逃脱? C:\test> 新星列表 | grep -V '----' | sed 's/^[^|]\+|//g' | sed 's/|(.)/,\1/g' | tr'|' '\n' grep: unrecognized option '----' Usage: grep [OPTION]... PATTERN [FILE]... 尝试 'grep --help' 获取更多信息。
      • 它不抱怨 v ,它不喜欢破折号:grep: unrecognized option '----'
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-07-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多