无法使用pyparsing set_parse_action()从字符串中去除空格

问题描述 投票:0回答:1

我有一个通用的“文本块”元素,我从文档中复制了空白剥离代码:

import pyparsing as pp

text_block = pp.Group(
    pp.OneOrMore(
        pp.SkipTo(pp.LineEnd()) + pp.LineEnd().suppress(),
        stopOn=pp.StringEnd() | (pp.LineStart() + (pp.Literal("E)") | pp.Literal("F)")))
    )
).set_parse_action(pp.token_map(str.strip))

不幸的是,这会返回一个错误:

失败异常:类型错误:“str”对象的描述符“strip” 不适用于“ParseResults”对象

我用函数替换了

token_map
的使用:

def _strip_whitespace(tokens):
    return [token.str.strip() for token in tokens]

text_block = pp.Group(
    pp.OneOrMore(
        pp.SkipTo(pp.LineEnd()) + pp.LineEnd().suppress(),
        stopOn=pp.StringEnd() | (pp.LineStart() + (pp.Literal("E)") | pp.Literal("F)")))
    )
).set_parse_action(_strip_whitespace)

...但现在它删除了所有文本(!)

python string whitespace pyparsing removing-whitespace
1个回答
0
投票

Pyparsing 默认情况下会自动处理 ParseResults 中的空格剥离

pyparsing 模块处理一些在编写文本解析器时通常令人烦恼的问题:

    额外或缺失的空格(上面的程序还将处理“Hello,World!”、“Hello , World !”等)
  • 带引号的字符串
  • 嵌入评论
因此,除非您配置/指示它专门捕获空格,否则无需删除空格,因为它通常会自动删除。

SkipTo()

 是可以捕获空白的 
ParserElements
 之一,因为它捕获当前解析位置和跳到字符之间的 
所有内容。这就是为什么,在 SkipTo
表解析示例中,他们在 
token.strip()
的解析操作中使用
SkipTo
但是

只有

解析器的SkipTo元素需要剥离,并且您试图剥离所有标记,这是一个非常糟糕的主意,因为除了明确定义的情况外,不会有任何空格。因此,如果您要在解析操作中应用

str.strip
,则应该将
just
放在 SkipTo 上。
他们给出的 

AtLineStart

示例对于此类匹配更为典型,通过

pp.rest_of_line
匹配每一行(这也会抓取空格):
test = '''\
AAA this line
AAA and this line
  AAA but not this one
B AAA and definitely not this one
'''

for t in (AtLineStart('AAA') + rest_of_line).search_string(test):
    print(t)

对于您的文本块,您
可以

只需跳到结束标记来抓取块中的所有行,然后在处理结果时处理剥离和分割: block_start_marker = pp.AtLineStart("(E") text_block = ( block_start_marker.suppress() + pp.SkipTo( pp.AtLineStart("E)") | pp.AtLineStart("F)") ) )

您将获得整个块(包括周围的换行符)的单个结果:

>>> text_block.parse_string("\n".join([ ... "(E", ... " This is ", ... " My text block ", ... "E)", ... ])) ParseResults(['\n This is \n My text block \n'], {})

或者,您可以进行逐行解析,但您只想将解析操作应用于 
SkipTo()

元素:

block_end_marker = pp.AtLineStart("E)") | pp.AtLineStart("F)")
text_block = (
    block_start_marker.suppress()
    + pp.OneOrMore(
        pp.SkipTo("\n").set_parse_action(pp.token_map(str.strip)),
        stop_on=block_end_marker
    )
)

>>> text_block.parse_string("\n".join([
...     "(E",
...     "    This is   ",
...     "   My text block  ",
...     "E)",
... ]))
ParseResults(['This is', 'My text block'], {})
	
© www.soinside.com 2019 - 2024. All rights reserved.