python - parseString 有效,scanString 失败?

标签 python pyparsing

在 parseString 给出正确结果的情况下让 scanString 工作时出现问题。

这个序列有效:

alpha_rev = pyp.Word(pyp.alphas, max=2)
num_rev = pyp.Word('123456789', max=2)
space = pyp.White(ws=" ").suppress()

revisionExpr = (
    pyp.StringStart().leaveWhitespace() +
    space +
    pyp.Combine(alpha_rev + 
    pyp.Optional(num_rev)("rev"))
    )

rev_string = ' K        WI, This is the title'

for match_str, start, end in (
    revisionExpr.scanString(rev_string, maxMatches=1)):
    print match_str

['K']

有时会有“Rev”或“Rev.”。修订前;这失败了:

revisionExpr = (
    pyp.StringStart().leaveWhitespace() +
    space +
    pyp.Combine(alpha_rev + 
    pyp.Optional(num_rev)("rev"))
    |
    pyp.CaselessLiteral("Rev") + pyp.Optional('.') + 
    pyp.Combine(alpha_rev + 
    pyp.Optional(num_rev)("rev"))
    )

for match_str, start, end in (
    revisionExpr.scanString(rev_string, maxMatches=1)):
    print match_str

print match_str
NameError: name 'match_str' is not defined

为什么是“|”导致匹配失败?请注意,这适用于第一个和第二个示例:

revisionTokens = revisionExpr.parseString(rev_string)

如果我将最后一个示例的第二部分(在“|”之后)提取为类似于第一个示例的形式,那么如果我添加“Rev.”,它就会起作用。在 rev_string 中的“K”前面。不幸的是,第一个表达式中的前导空格是唯一标识修订字符串所必需的,否则,在此示例中,“WI”将匹配。

我正在尝试使用 scanString 而不是 parseString,因为它会返回匹配的开始和结束位置,这有助于稍后的处理。

最佳答案

问题是您的“或”运算符(“|”)只直接查看其左右两侧的元素。您没有正确分组您的语法元素。这是您的语法的更多分解:

left_expr = pyp.Combine(alpha_rev + pyp.Optional(num_rev)("rev")
right_expr = pyp.CaselessLiteral("Rev")

joined_expr = left_expr | right_expr

final_expr = (pyp.StringStart().leaveWhitespace() +
    space +
    joined_expr +
    pyp.Optional('.') +
    pyp.Combine(alpha_rev +
      pyp.Optional(num_rev)("rev"))
    )

如您所见,这并不是您想要的 - 它将查找文本“Rev”或实际修订,然后是另一个修订。表达式的固定版本如下:

revisionExpr = (
    pyp.StringStart().leaveWhitespace() +
    space +
    (
        pyp.Combine(alpha_rev +
            pyp.Optional(num_rev)("rev")
        )
        |
        (
            pyp.CaselessLiteral("Rev") + 
            pyp.Optional('.') +
            pyp.Combine(alpha_rev +
                pyp.Optional(num_rev)("rev"))
        )
    )
)

但是,您可以使语法更简洁:

revisionExpr = (
    pyp.StringStart().leaveWhitespace() +
    space +
    pyp.Suppress(
        pyp.Optional(
            pyp.CaselessLiteral("Rev") + 
            pyp.Optional('.')
        )
    ) +
    pyp.Combine(
        alpha_rev +
        pyp.Optional(num_rev)("rev")
    )
)

在此版本中,您只需标记“Rev”。文本作为可选的,位于预期的位置,而不是为解析提供仅解析修订或“Rev”的选项。 + 修订。这避免了使用“|”引起的任何问题根本没有运营商。

不要忘记 PyParsing 使用运算符重载来提供更好的语法,如果语法导致混淆(如在这种情况下),您最好只使用长格式方法调用,例如“pyp.Or(a, b)".

关于python - parseString 有效,scanString 失败?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12927787/

相关文章:

python - Peewee ORM 中的 before_save() 和 after_save() Hook ?

python - 我需要根据两列数据帧生成新列,如何才能更快?

python - 带有换行符的文本文件到数据框 pandas 中

python - PyParsing:并非所有标记都传递给 setParseAction()

python - 如何使用 python、pyparsing 按顺序解析文件中的行/匹配足够的结果?

python - 用关键字或纯文本匹配多行

python - 拟合多峰分布

python - 接收 "detail": "not found" for detail view with Django Rest Framework

python - Pyparsing:在结果名称中获取标记位置

python - 使用 dump() 和 asXML() 函数时 pyparsing 不同的结果