使用 pyparsing 解析冒号分隔字符串的最佳方法是什么

What is the best way to parse a colon separated string with pyparsing

这是数据:

C:/data/my_file.txt.c:10:0x21:name1:name2:0x10:1:OK
C:/data/my_file2.txt.c:110:0x1:name2:name5:0x12:1:NOT_OK
./data/my_file3.txt.c:110:0x1:name2:name5:0x12:10:OK

我想得到这个结果

[C:/data/my_file.txt.c, 10, 0x21, name1, name2, 0x10, 1, OK]
[C:/data/my_file2.txt.c, 110, 0x1, name2, name5, 0x12, 1, NOT_OK]
[./data/my_file3.txt.c, 110, 0x1, name2, name5, 0x12, 10, OK]

我知道如何使用一些代码或字符串拆分之类的东西来做到这一点,但我正在使用 pyparsing 寻找一个不错的解决方案。我的问题是文件路径的 :/。

附加问题我使用一些代码从记录中删除评论和其他内容,因此原始数据如下所示:

text = """C:/data/my_file.txt.c:10:0x21:name1:name2:0x10:1:OK
C:/data/my_file2.txt.c:110:0x1:name2:name5:0x12:1:NOT_OK
// comment
./data/my_file3.txt.c:110:0x1:name2:name5:0x12:10:OK
---- 
ok
"""

我现在在解析之前删除“//”、"ok" 和“---”

所以现在我还有下一个问题:

第一个问题的一些补充。到目前为止,我从数据文件中提取了上面的行——效果很好。所以我逐行读取文件并解析它。但是现在我发现可以使用 parseFile 来解析整个文件。所以我想我可以剥离我的一些代码并改用 parseFile 。所以我想解析的文件有一个额外的页脚。

C:/data/my_file.txt.c:10:0x21:name1:name2:0x10:1:OK
C:/data/my_file2.txt.c:110:0x1:name2:name5:0x12:1:NOT_OK
./data/my_file3.txt.c:110:0x1:name2:name5:0x12:10:OK: info message

-----------------------
3 Files 2 OK 1 NOT_OK
NOT_OK 

是否可以更改解析器以获得 2 个解析结果?

结果 1:

[['C:/data/my_file.txt.c', '10', '0x21', 'name1', 'name2', '0x10', '1', 'OK'],
 ['C:/data/my_file2.txt.c', '110', '0x1', 'name2', 'name5', '0x12', '1', 'NOT_OK'],
 ['./data/my_file3.txt.c', '110', '0x1', 'name2', 'name5', '0x12', '10', 'OK']]

Ignore the blank line   
Ignore this line => -----------------------

结果 2:

 [['3', 'Files', 2', 'OK’, '1', 'NOT_OK'],
 ['NOT_OK’],

所以我为此更改了代码:

    # define an expression for your file reference
one_thing = Combine(
    oneOf(list(alphas)) + ':/' +
    Word(alphanums + '_-./'))

# define a catchall expression for everything else (words of non-whitespace characters,
# excluding ':')
another_thing = Word(printables + " ", excludeChars=':')

# define an expression of the two; be sure to list the file reference first
thing = one_thing | another_thing

# now use plain old pyparsing delimitedList, with ':' delimiter
list_of_things = delimitedList(thing, delim=':')

list_of_other_things = Word(printables).setName('a')
# run it and see...
parse_ret = OneOrMore(Group(list_of_things | list_of_other_things)).parseFile("data.file")
parse_ret.pprint()

我得到了这个结果:

[['C:/data/my_file.txt.c', '10', '0x21', 'name1', 'name2', '0x10', '1', 'OK'],
['C:/data/my_file2.txt.c','110', '0x1', 'name2', 'name5', '0x12', '1', 'NOT_OK'],
['./data/my_file3.txt.c', '110', '0x1', 'name2', 'name5', '0x12', '10', 'OK', 'info message'],
['-----------------------'],
['3 Files 2 OK 1 NOT_OK'],
['NOT_OK']]

所以我可以接受这个但是是否可以将结果分成两个命名结果?我搜索了文档,但没有找到任何有用的东西。顺便说一下,有没有关于pyparsing的好教程?

谢谢

查看 pyparsing 描述的嵌入式注释:

from pyparsing import *

text = """C:/data/my_file.txt.c:10:0x21:name1:name2:0x10:1:OK
C:/data/my_file2.txt.c:110:0x1:name2:name5:0x12:1:NOT_OK
// blah-de blah blah blah
./data/my_file3.txt.c:110:0x1:name2:name5:0x12:10:OK"""

# define an expression for your file reference
one_thing = Combine(
    oneOf(list(alphas.upper())) + ':/' + 
    Word(alphanums + '_-./'))

# define a catchall expression for everything else (words of non-whitespace characters, 
# excluding ':')
another_thing = Word(printables, excludeChars=':')

# define an expression of the two; be sure to list the file reference first
thing = one_thing | another_thing

# now use plain old pyparsing delimitedList, with ':' delimiter
list_of_things = delimitedList(thing, delim=':')

parser = OneOrMore(Group(list_of_things))

# ignore comments starting with double slash
parser.ignore(dblSlashComment)

# run it and see...
parser.parseString(text).pprint()

打印:

[['C:/data/my_file.txt.c', '10', '0x21', 'name1', 'name2', '0x10', '1', 'OK'],
 ['C:/data/my_file2.txt.c', '110', '0x1', 'name2', 'name5', '0x12', '1', 'NOT_OK'],
 ['./data/my_file3.txt.c', '110', '0x1', 'name2', 'name5', '0x12', '10', 'OK']]

使用回复:

myList = ["C:/data/my_file.txt.c:10:0x21:name1:name2:0x10:1:OK", "C:/data/my_file2.txt.c:110:0x1:name2:name5:0x12:1:NOT_OK", "./data/my_file3.txt.c:110:0x1:name2:name5:0x12:10:OK"]

for i in myList:
    newTxt =  re.sub(r':', ",", i)
    newTxt = re.sub(r',/', ":/", newTxt)
    print newTxt

所以我没有找到 delimitedList 和 parseFile 的解决方案,但我找到了一个适合我的解决方案。

from pyparsing import *

data = """
C: / data / my_file.txt.c:10:0x21:name1:name2:0x10:1:OK
C: / data / my_file2.txt.c:110:0x1:name2:name5:0x12:1:NOT_OK
./ data / my_file3.txt.c:110:0x1:name2:name5:0x12:10:OK: info message

-----------------------
3 Files 2 OK 1 NOT_OK
NOT_OK
"""

if __name__ == '__main__':

# define an expression for your file reference
entry_one = Combine(
    oneOf(list(alphas)) + ':/' +
    Word(alphanums + '_-./'))

entry_two = Word(printables + ' ', excludeChars=':')
entry = entry_one | entry_two

delimiter = Literal(':').suppress()
tc_result_line = Group(entry.setResultsName('file_name') + delimiter + entry.setResultsName(
    'line_nr') + delimiter + entry.setResultsName('num_one') + delimiter + entry.setResultsName('name_one') + delimiter + entry.setResultsName(
    'name_two') + delimiter + entry.setResultsName('num_two') + delimiter + entry.setResultsName('status') + Optional(
    delimiter + entry.setResultsName('msg'))).setResultsName("info_line")

EOL = LineEnd().suppress()
SOL = LineStart().suppress()
blank_line = SOL + EOL

tc_summary_line = Group(Word(nums).setResultsName("num_of_lines") + "Files" + Word(nums).setResultsName(
    "num_of_ok") + "OK" + Word(nums).setResultsName("num_of_not_ok") + "NOT_OK").setResultsName(
    "info_summary")
tc_end_line = Or(Literal("NOT_OK"), Literal('Ok')).setResultsName("info_result")

# run it and see...
pp1 = tc_result_line | Optional(tc_summary_line | tc_end_line)
pp1.ignore(blank_line | OneOrMore("-"))

result = list()
for l in data.split('\n'):
    result.append((pp1.parseString(l)).asDict())
# delete empty results
result = filter(None, result)

for r in result:
    print(r)

pass

结果:

{'info_line': {'file_name': 'C', 'num_one': '10', 'msg': '1', 'name_one':   '0x21', 'line_nr': '/ data / my_file.txt.c', 'status': '0x10', 'num_two': 'name2', 'name_two': 'name1'}}
{'info_line': {'file_name': 'C', 'num_one': '110', 'msg': '1', 'name_one': '0x1', 'line_nr': '/ data / my_file2.txt.c', 'status': '0x12', 'num_two': 'name5', 'name_two': 'name2'}}
{'info_line': {'file_name': './ data / my_file3.txt.c', 'num_one': '0x1', 'msg': 'OK', 'name_one': 'name2', 'line_nr': '110', 'status': '10', 'num_two': '0x12', 'name_two': 'name5'}}
{'info_summary': {'num_of_lines': '3', 'num_of_ok': '2', 'num_of_not_ok': '1'}}
{'info_result': ['NOT_OK']}