pyparsing 可以吐出导致 ParseException 的文本吗?

Can pyparsing spit out the text which causes a ParseException?

使用pyparsing我尝试用

这样的复合表达式解析一些文本
a = pp.Word(pp.alphas).setResultsName('A')
b = pp.Word(pp.nums).setResultsName('B')
c = pp.Word(pp.alphas).setResultsName('C')
expr = a + b + c

parseString 失败并出现异常

ParseException: Expected W:(0123...) (at char 7), (line:1, col:8)

到目前为止一切顺利。但是,为了更好地理解发生了什么,是否可以让 pyparsing/parseString 直接告诉我输入字符串 中的 字符不匹配? (当然,我可以根据异常文本中的信息自行计算。)

此外,是否可以查看在哪个子表达式(a、b 或 c) 中引发了异常?

Pyparsing 异常包括一个方法 markInputline(),它将打印输入字符串的最后一行和一个发生异常的标记:

import pyparsing as pp
a = pp.Word(pp.alphas).setResultsName('A')
b = pp.Word(pp.nums).setResultsName('B')
c = pp.Word(pp.alphas).setResultsName('C')
expr = a + b + c
try:
    expr.parseString("lskdjf lskdjf sdlkfj")
except ParseException as pe:
    print(pe.markInputline())

lskdjf >!<lskdjf sdlkfj

(如果您不喜欢'>!<',您可以指定不同的标记。)

这是我使用的另一种方法,它利用了 ParseException 的 col 和 line 属性:

alphaword = pp.Word(pp.alphas).setName('alphaword')
numword = pp.Word(pp.nums).setName('numword')
expr = alphaword('A') + numword('B') + alphaword('C')
try:
    expr.parseString('sldkj slkdj sldkj')
except ParseException as pe:
    print(pe.line)
    print(' '*(pe.col-1) + '^')
    print(pe)

sldkj slkdj sldkj
      ^
Expected numword (at char 6), (line:1, col:7)

其他几点:

  • 我已经使用 setName() 为表达式本身命名,这样异常消息就更具可读性了。请注意setName和setResultsName的区别。

  • 我使用调用语法来定义结果名称。在实践中(或者只是出于懒惰)我发现“.setResultsName”方法调用确实有损于代码的语法定义部分。所以代替 expr.setResultsName('xyz'),你可以写 expr('xyz').