我需要指定一个定义为
ambn
的表达式,这样:
m
+ n
= t
; t
已修复m
<= t
- 1n
<= t
这是当前代码的样子,经过简化:
from pyparsing import Char, Combine
def ab(t):
first = Char('a')[0, t - 1]
second = Char('b')[1, t]
expression = first + second
expression.add_condition(
lambda result: len(result) == t,
message = f'Total length must be {t}'
)
return Combine(expression)
然而,表达式消耗了它能找到的所有内容,并对该结果调用条件函数而不回溯。例如:
grammar = (ab(4) | Char('b'))[1, ...].set_name('grammar')
grammar.parse_string('abbbb', parse_all = True)
ParseException: Expected grammar, found 'abbbb' (at char 0), (line:1, col:1)
我想要的结果是
['abbb', 'b']
,如果将有问题的表达式指定为:
expression = Or([
Char('a')[m] + Char('b')[t - m]
for m in range(0, t)
])
...但这看起来不必要的冗长。
有更好的方法吗?
我使用“|”重写了你的第二种方法运算符,创建 MatchFirst 表达式而不是 Or:
a = pp.Char('a')
b = pp.Char('b')
def ab(t):
expr = b[t]
for i in range(1, t):
expr |= a[i] + b[t-i]
return pp.Combine(expr)
它还使用
b[t]
定义第一项,并使用从 1 开始的范围,而不是默认的 0。
然后我使用 run_tests 进行测试:
ab5 = ab(5)
ab5.run_tests("""\
bbbbb
abbbb
aabbb
aaabb
aaaab
""")
ab4b = ab(4) + b
ab4b.run_tests("""\
bbbbb
abbbb
aabbb
aaabb
""")
两种表达方式都给出了预期的结果。
您使用条件的第一种方法因您所说的确切原因而失败 - 'b' 的重复不知道何时停止,因此它会读取超出并进入 'b' ,而 'b' 旨在被解析为第二项。 (与正则表达式不同,pyparsing 不执行任何回溯)。
因此,我没有使用条件,而是将 ab() 的 b 项更改为 Forward,并向 a 项添加了解析操作,以将表达式插入到包含正确数量的 b 的 b 项中。
def ab(t):
a_s = a[0, t-1]
b_s = pp.Forward()
expr = a_s + b_s
def dynamic_b_term(a_chars):
b_s << b[t - len(a_chars)]
a_s.add_parse_action(dynamic_b_term)
return pp.Combine(expr)
这也通过了
ab(5)
和 ab(4) + b
的 run_tests。