"A or B or both" 的表达式组合
Expression-combination of "A or B or both"
这是我目前拥有的:
_filter_date_range = pp.Group(_keyword_date + pp.Group(
pp.Group(_function_before + _argument_string) & pp.Group(_function_after + _argument_string)
))
由于我使用了Each
(&
),所以这两个表达式都是必需的。但我想允许:
- 甲或乙
- 或两者
- 但至少有一个
- 顺序不限
如果我将两个组都设为 Optional
,我也不会允许,这是我不希望的。那么有什么我可以用的吗?
以下是三种可能的解决方案:
from pyparsing import Literal, OneOrMore, Optional
A = Literal("A")
B = Literal("B")
language = OneOrMore( A | B )
assert language.matches("A")
assert language.matches("B")
assert language.matches("A B")
assert language.matches("B A")
assert language.matches("A A")
assert language.matches("B B")
assert language.matches("A B A B")
assert not language.matches("")
def EitherOrBoth(a, b):
return (a + b) | (b + a) | a | b
language = EitherOrBoth(A, B)
assert language.matches("A")
assert language.matches("B")
assert language.matches("A B")
assert language.matches("B A")
assert not language.matches("A A")
assert not language.matches("B B")
assert not language.matches("A B A B")
assert not language.matches("")
def EitherOrBoth(a, b):
return (a + Optional(b)) | (b + Optional(a))
language = EitherOrBoth(A, B)
assert language.matches("A")
assert language.matches("B")
assert language.matches("A B")
assert language.matches("B A")
assert not language.matches("A A")
assert not language.matches("B B")
assert not language.matches("A B A B")
assert not language.matches("")
@Rob 的第三个选项 EitherOrBoth
在这种情况下效果很好,我认为,但是当你必须处理 3 个或更多可能出现的表达式时,pyparsing 的 Each
真正发挥作用任意顺序:
from pyparsing import Literal, Each
A = Literal("A")
B = Literal("B")
C = Literal("C")
def noMoreThanOneOfEachAndAtLeastOne(exprs):
ret = Each(map(Optional, exprs))
ret.addCondition(bool)
return ret
language = noMoreThanOneOfEachAndAtLeastOne([A,B,C])
assert language.matches("A")
assert language.matches("B")
assert language.matches("A C B")
assert language.matches("C A")
assert not language.matches("A A")
assert not language.matches("B B")
assert not language.matches("A B A B")
assert not language.matches("")
addCondition
是 pyparsing 的一个相当新的补充,addParseAction
的一个变体。 addCondition
接受一个可调用对象(具有与 addParseAction
相同的调用签名支持),它必须 return 一个布尔值。如果它 returns False,则该条件将导致引发 ParseException。 (这是使用解析操作作为验证器的用例的简化。)在这种情况下,我们所需要的只是 Python 内置 bool
,因为 ParseResults 与所有 Python 一样本机序列,当为空时求值为 False,否则为 True。
这是我目前拥有的:
_filter_date_range = pp.Group(_keyword_date + pp.Group(
pp.Group(_function_before + _argument_string) & pp.Group(_function_after + _argument_string)
))
由于我使用了Each
(&
),所以这两个表达式都是必需的。但我想允许:
- 甲或乙
- 或两者
- 但至少有一个
- 顺序不限
如果我将两个组都设为 Optional
,我也不会允许,这是我不希望的。那么有什么我可以用的吗?
以下是三种可能的解决方案:
from pyparsing import Literal, OneOrMore, Optional
A = Literal("A")
B = Literal("B")
language = OneOrMore( A | B )
assert language.matches("A")
assert language.matches("B")
assert language.matches("A B")
assert language.matches("B A")
assert language.matches("A A")
assert language.matches("B B")
assert language.matches("A B A B")
assert not language.matches("")
def EitherOrBoth(a, b):
return (a + b) | (b + a) | a | b
language = EitherOrBoth(A, B)
assert language.matches("A")
assert language.matches("B")
assert language.matches("A B")
assert language.matches("B A")
assert not language.matches("A A")
assert not language.matches("B B")
assert not language.matches("A B A B")
assert not language.matches("")
def EitherOrBoth(a, b):
return (a + Optional(b)) | (b + Optional(a))
language = EitherOrBoth(A, B)
assert language.matches("A")
assert language.matches("B")
assert language.matches("A B")
assert language.matches("B A")
assert not language.matches("A A")
assert not language.matches("B B")
assert not language.matches("A B A B")
assert not language.matches("")
@Rob 的第三个选项 EitherOrBoth
在这种情况下效果很好,我认为,但是当你必须处理 3 个或更多可能出现的表达式时,pyparsing 的 Each
真正发挥作用任意顺序:
from pyparsing import Literal, Each
A = Literal("A")
B = Literal("B")
C = Literal("C")
def noMoreThanOneOfEachAndAtLeastOne(exprs):
ret = Each(map(Optional, exprs))
ret.addCondition(bool)
return ret
language = noMoreThanOneOfEachAndAtLeastOne([A,B,C])
assert language.matches("A")
assert language.matches("B")
assert language.matches("A C B")
assert language.matches("C A")
assert not language.matches("A A")
assert not language.matches("B B")
assert not language.matches("A B A B")
assert not language.matches("")
addCondition
是 pyparsing 的一个相当新的补充,addParseAction
的一个变体。 addCondition
接受一个可调用对象(具有与 addParseAction
相同的调用签名支持),它必须 return 一个布尔值。如果它 returns False,则该条件将导致引发 ParseException。 (这是使用解析操作作为验证器的用例的简化。)在这种情况下,我们所需要的只是 Python 内置 bool
,因为 ParseResults 与所有 Python 一样本机序列,当为空时求值为 False,否则为 True。