匹配数据库输出(平衡括号、表格和行结构)并输出为列表?

0 投票
4 回答
595 浏览
提问于 2025-04-15 13:50

我想知道怎么处理下面的输入(可以逐行处理,也可以用正则表达式,或者两者结合):

Table[
    Row[
        C_ID[Data:12345.0][Sec:12345.0][Type:Double]
        F_ID[Data:17660][Sec:17660][Type:Long]
        NAME[Data:Mike Jones][Sec:Mike Jones][Type:String]
    ]

    Row[
        C_ID[Data:2560.0][Sec:2560.0][Type:Double]
    ...
    ]
]

里面有缩进,所以可以通过 \n\t 来分割(然后再清理一下 C_ID、F_ID 行中的多余制表符 \t 等等...)

我想要的输出是更适合在 Python 中使用的格式:

{'C_ID': 12345, 'F_ID': 17660, 'NAME': 'Mike Jones',....} {'C_ID': 2560, ....}

我试过逐行处理,然后用多个 splits() 来丢掉不需要的部分,保留需要的部分,但我相信还有更优雅、更快速的方法可以做到这一点...

4 个回答

0

这个很棒的页面列出了许多适合Python程序员使用的解析器。正则表达式不太适合用来匹配“平衡的括号”,不过页面上提到的那些第三方包都能很好地满足你的需求。

1

这里其实没有太多复杂的嵌套结构,所以你可以用正则表达式来处理。不过我更喜欢用pyparsing这个工具,所以这是我的解决方案:

from pyparsing import *

LBRACK,RBRACK,COLON = map(Suppress,"[]:")
ident = Word(alphas, alphanums+"_")
datatype = oneOf("Double Long String Boolean")

# define expressions for pieces of attribute definitions
data = LBRACK + "Data" + COLON + SkipTo(RBRACK)("contents") + RBRACK
sec = LBRACK + "Sec" + COLON + SkipTo(RBRACK)("contents") + RBRACK
type = LBRACK + "Type" + COLON + datatype("datatype") + RBRACK

# define entire attribute definition, giving each piece its own results name
attrDef = Group(ident("key") + data("data") + sec("sec") + type("type"))

# now a row is just a "Row[" and one or more attrDef's and "]"
rowDef = Group("Row" + LBRACK + Group(OneOrMore(attrDef))("attrs") + RBRACK)

# this method will process each row, and convert the key and data fields
# to addressable results names
def assignAttrs(tokens):
    ret = ParseResults(tokens.asList())
    for attr in tokens[0].attrs:
        # use datatype mapped to function to convert data at parse time
        value = {
            'Double' : float,
            'Long' : int,
            'String' : str,
            'Boolean' : bool,
            }[attr.type.datatype](attr.data.contents)
        ret[attr.key] = value
    # replace parse results created by pyparsing with our own named results
    tokens[0] = ret
rowDef.setParseAction(assignAttrs)

# a TABLE is just "Table[", one or more rows and "]"
tableDef = "Table" + LBRACK + OneOrMore(rowDef)("rows") + RBRACK

test = """
Table[    
  Row[
    C_ID[Data:12345.0][Sec:12345.0][Type:Double]
    F_ID[Data:17660][Sec:17660][Type:Long]
    NAME[Data:Mike Jones][Sec:Mike Jones][Type:String]
  ]    
  Row[
    C_ID[Data:2560.0][Sec:2560.0][Type:Double] 
    NAME[Data:Casey Jones][Sec:Mike Jones][Type:String]
  ]
]"""

# now parse table, and access each row and its defined attributes
results = tableDef.parseString(test)
for row in results.rows:
    print row.dump()
    print row.NAME, row.C_ID
    print

输出结果是:

[[[['C_ID', 'Data', '12345.0', 'Sec', '12345.0', 'Type', 'Double'],...
- C_ID: 12345.0
- F_ID: 17660
- NAME: Mike Jones
Mike Jones 12345.0

[[[['C_ID', 'Data', '2560.0', 'Sec', '2560.0', 'Type', 'Double'], ...
- C_ID: 2560.0
- NAME: Casey Jones
Casey Jones 2560.0

在assignAttrs中分配的结果名称让你可以通过名称访问每一个属性。要检查某个名称是否被遗漏,只需测试一下“if not row.F_ID:”就可以了。

3

用正则表达式解析递归结构真是麻烦,因为你需要保持状态。

与其这样,不如使用 pyparsing 或者其他真正的解析器。

有些人喜欢 PLY,因为它遵循传统的 Lex/Yacc 结构。

撰写回答