pyparsing不嵌套列表...为什么?

4 投票
1 回答
724 浏览
提问于 2025-04-16 07:22

出于某种原因,pyparsing没有为我的字符串创建嵌套列表:

rank = oneOf("2 3 4 5 6 7 8 9 T J Q K A")
suit = oneOf("h c d s")
card = rank + Optional(suit)

suit_filter = oneOf("z o")
hand = card + card + Optional(suit_filter)

greater = Literal("+")
through = Literal("-")
series = hand + Optional(greater | through + hand)

series_split = Literal(",")
hand_range = series + ZeroOrMore(series_split + series)

hand_range.parseString('22+,AKo-ATo,KQz')

>> ['2', '2', '+', ',', 'A', 'K', 'o', '-', 'A', 'T', 'o', ',', 'K', 'Q', 'z']

我不太明白为什么pyparsing没有在22+、AKo-ATo和KQz周围创建列表(或者说没有更深层次的嵌套)。我错过了什么呢?

1 个回答

8

Pyparsing没有把这些标记分组,是因为你没有告诉它要这样做。Pyparsing的默认行为是把所有匹配的标记简单地放在一个列表里。如果你想把标记分组,就需要用pyparsing的Group表达式把你想分组的部分包裹起来。在你的例子中,把series从:

series = hand + Optional(greater | through + hand)

改成

series = Group(hand + Optional(greater | through + hand))

另外,我建议你不要像在series中那样自己实现一个用逗号分隔的列表,而是使用pyparsing提供的助手delimitedList

hand_range = delimitedList(series)

delimitedList默认是用逗号作为分隔符,但你可以用任何字符(甚至是完整的pyparsing表达式)作为delim参数。分隔符本身不会出现在结果中,因为delimitedList认为分隔符只是用来分开重要部分的,列表元素之间的分隔。

在做了这两个修改后,解析的结果就会更接近你想要的样子:

[['2', '2', '+'], ['A', 'K', 'o', '-', 'A', 'T', 'o'], ['K', 'Q', 'z']]

我猜你可能还想在hand的定义周围加上Group,这样也能更好地组织这些结果。

如果这是一个需要以某种方式进行评估的表达式(比如扑克手牌),那么请查看pyparsing wiki上的这些示例,它们使用类作为解析动作来构建可以评估等级或布尔值等的对象。

http://pyparsing.wikispaces.com/file/view/invRegex.py

http://pyparsing.wikispaces.com/file/view/simpleBool.py

http://pyparsing.wikispaces.com/file/view/eval_arith.py

如果你为这些表达式构建对象,那么就不需要使用Group了。

撰写回答