【问题标题】:how to reformat data with dynamic number of columns如何使用动态列数重新格式化数据
【发布时间】:2012-12-05 10:39:11
【问题描述】:

我的数据形式是类别和值在同一行中,由“;”分隔如下:

{{category1;value}, {category2;value}, {category3;value} ....}}

每一行的数据可能有不同数量的类别。因此,第一行可能有 category1 到 category5,而第二行可能有 category1 到 category10。不过,类别总是按顺序排列的。

我需要解析数据并创建一个新文件,以便在列标题中包含类别的名称和在相应行中的值。

category1        category2        category3       category4    ....
 value             value             value          value

但是由于我不能说可能有多少类别,所以我需要添加每个新列。因此,解析第一行我会知道有 5 列(cat1 到 cat5),但是对于第二行,我必须将 cat6 的列添加到 cat10 等等。

任何想法如何做到这一点。任何 Linux bash 脚本都可以,但我更喜欢 python。

【问题讨论】:

  • 类别或值是否可以包含大括号?
  • @unutbu 这些值可以有任何字符。但是类别周围有大括号;值对也如图所示。
  • 如果value 可以包含任何字符,应该使用什么规则来确定{{category1;value}, {category2;value}} 没有被解析为具有一个类别category1,其值为value}, {category2;value
  • 这是另一个棘手的问题。我正在查看它,以便可以通过查看开头 { 然后查找 } 来找到任何对,以结束该对。让我们假设值中没有任何以}结尾的字符。
  • 那么{{category1;val},{ue}} 应该是语法错误,还是应该将其解析为具有category1val},{ue 的类别?如果是后者,那我觉得问题就比较难了。

标签: python bash text-parsing


【解决方案1】:

鉴于 cmets,听起来 category 可以包含除分号以外的任何字符,value 可以包含除右大括号之外的任何字符,因为这些字符会终止 categoryvalue太快了。

在这种情况下,可以使用正则表达式来匹配模式。

import re

def report(text):
    # Remove surrounding whitespace and braces
    text = text.strip()[1:-1]   
    pairs = re.findall(
        r'''\{      # literal open brace
            (.+?)   # one-or-more characters, stop at the first
            ;       # literal semicolon
            (.+?)   # one-or-more characters, stop at the first
            \}      # literal closed brace
            ''', text, re.VERBOSE)
    categories, values = zip(*pairs)
    widths = [max(map(len, item)) for item in pairs]
    fmt = '{x:^{w}}'
    for row in (categories, values):
        print('    '.join([fmt.format(x = x, w = w) for x, w in zip(row, widths)]))

tests = """\
{{category1;value}, {category2;value}}
{{category1;value}, {category2;value}, {category3;value}}
{{categ{,ory1;val;ue}, {category2;val{ue}, {category3;value}}
""".splitlines()

for test in tests:
    report(test)

产量

category1    category2
  value        value  
category1    category2    category3
  value        value        value  
categ{,ory1    category2    category3
  val;ue        val{ue        value  

【讨论】:

    【解决方案2】:

    可能有很多方法可以做到这一点,但一种可能的方法是

    >>> rows = data.translate(None,"{}").replace(";",",").split(",")
    >>> rows[::2]
    ['category1', ' category2', ' category3']
    >>> rows[1::2]
    ['value', 'value', 'value']
    

    和上面的一个小变化

    >>> rows = dict(e.split(';') for e in data.translate(None,"{}").split(","))
    >>> rows.keys()
    ['category1', ' category2', ' category3']
    >>> rows.values()
    ['value', 'value', 'value']
    

    还有一个使用正则表达式的变体

    >>> rows = re.split("[\{\},; ]+",data)[1:-1]
    >>> rows[::2]
    ['category1', 'category2', 'category3']
    >>> rows[1::2]
    ['value', 'value', 'value']
    

    【讨论】:

      猜你喜欢
      • 2019-11-22
      • 2011-11-14
      • 1970-01-01
      • 1970-01-01
      • 2012-01-19
      • 1970-01-01
      • 2011-03-21
      • 2021-05-08
      • 1970-01-01
      相关资源
      最近更新 更多