通常在 pyparsing 中展平返回的列表

Generally flatten returned lists in pyparsing

这个解释起来有点冗长,所以请耐心等待:使用 pyparsing 我必须分析许多文本部分,例如:

first multi segment part 123 45 67890 third multi segment part

------------^----------- -----^------ ------------^-----------
  Part A: alpha words    B: num words   Part C: alpha words

我尝试对每个部分使用 pp.OneOrMore

a = pp.OneOrMore(pp.Word(pp.alphas)).setName("PART_A")('A')
b = pp.OneOrMore(pp.Word(pp.nums)).setName("PART_B")('B')
c = pp.OneOrMore(pp.Word(pp.alphas)).setName("PART_C")('C')
expr = a + b + c

当我 运行 通过字符串 "first multi segment part 123 45 67890 third multi segment part" 我得到

- A: ['first', 'multi', 'segment', 'part']
- B: ['123', '45', '67890']
- C: ['third', 'multi', 'segment', 'part']

但是我希望所有结果像这样扁平化:

- A: 'first multi segment part'
- B: '123 45 67890'
- C: 'third multi segment part'

为此,我可以使用 setParseAction 函数。因为我将有很多使用此功能的构造我扩展了 OneOrMore class 喜欢这样:

class OneOrMoreJoined(pp.OneOrMore):
    """OneOrMore with results joined to one string"""
    def __init__( self, expr, stopOn=None, joinString=' '):
        super(OneOrMoreJoined,self).__init__(expr, stopOn=stopOn)
        self.setParseAction(joinString.join)

有了这个 class 我得到了想要的结果。 :-)

但是,如果我想加入序列 d1 + d2,我该怎么办?:

d1 = pp.Word(pp.nums).setName("PART_D1")
d2 = pp.Word(pp.alphas).setName("PART_D2")
expr = (d1 + d2)('D')

当然我创建了一个新的 class AndJoined 并使用了 AndJoined(d1,d2),但是后来我失去了很好的符号 d1 + d2.

有没有一种通用的方法可以使结果变平? 我当然可以在检索到 dict 后手动 外部 展平 ParseResult,但我怀疑有一种简单的方法可以表达这个 里面 pyparsing...

最简单的就是写一个这样的小帮手:

joiner = lambda expr: expr.addParseAction(' '.join)

然后在语法中的任何位置插入 joiner

a_b_c = joiner(a + b + c | d + Optional(e))

只需确保传递给 joiner 的令牌只是单级令牌。如果它们是嵌套的,那么您可能需要一个扁平化例程,但这很容易通过将 joiner 写为:

joiner = lambda expr: expr.addParseAction(flatten, ' '.join)