Pyparsing中的关键字匹配:非贪婪的令牌啜食

Esc*_*alo 5 python grammar parsing pyparsing

Pythonistas:

假设您要使用Pyparsing解析以下字符串:

'ABC_123_SPEED_X 123'
Run Code Online (Sandbox Code Playgroud)

分别ABC_123是一个标识符; SPEED_X是一个参数,123是一个值.我想到了以下使用Pyparsing的BNF:

Identifier = Word( alphanums + '_' )
Parameter = Keyword('SPEED_X') or Keyword('SPEED_Y') or Keyword('SPEED_Z')
Value = # assume I already have an expression valid for any value
Entry = Identifier + Literal('_') + Parameter + Value
tokens = Entry.parseString('ABC_123_SPEED_X 123')
#Error: pyparsing.ParseException: Expected "_" (at char 16), (line:1, col:17)
Run Code Online (Sandbox Code Playgroud)

如果我从中间删除下划线(并相应地调整Entry定义),它会正确解析.

如何使这个解析器变得有点懒惰,并等到它与关键字匹配(而不是将整个字符串作为标识符啜饮并等待_,而不存在.

谢谢.

[注意:这完全改写了我的问题; 我没有意识到真正的问题是什么]

got*_*nes 7

我的答案是基于这个,因为你要做的是得到一个非贪婪的比赛.似乎这很难在pyparsing中发生,但通过一些聪明和妥协​​并非不可能.以下似乎有效:

from pyparsing import *
Parameter = Literal('SPEED_X') | Literal('SPEED_Y') | Literal('SPEED_Z')
UndParam = Suppress('_') + Parameter
Identifier = SkipTo(UndParam)
Value = Word(nums)
Entry = Identifier + UndParam + Value
Run Code Online (Sandbox Code Playgroud)

当我们从交互式解释器运行它时,我们可以看到以下内容:

>>> Entry.parseString('ABC_123_SPEED_X 123')
(['ABC_123', 'SPEED_X', '123'], {})
Run Code Online (Sandbox Code Playgroud)

请注意,这是妥协; 因为我使用SkipTo,Identifier可以充满邪恶,令人作呕的角色,而不仅仅是美丽alphanums的偶尔下划线.

编辑:感谢Paul McGuire,我们可以通过设置Identifier以下内容来制作一个真正优雅的解决方案:

Identifier = Combine(Word(alphanums) +
        ZeroOrMore('_' + ~Parameter + Word(alphanums)))
Run Code Online (Sandbox Code Playgroud)

让我们来看看它是如何工作的.首先,忽略外在Combine; 我们稍后会谈到这个.从Word(alphanums)我们知道我们将获得'ABC'参考字符串的一部分,'ABC_123_SPEED_X 123'.重要的是要注意,在这种情况下,我们不允许"单词"包含下划线.我们将它分别构建到逻辑中.

接下来,我们需要在'_123'不吸吮的情况下捕获零件'_SPEED_X'.我们也在ZeroOrMore这一点上跳过并稍后再回过头来.我们从下划线开始Literal,但我们可以使用just '_',这将使我们成为领先的下划线,但不是全部'_123'.从本质上讲,我们会设置另一个Word(alphanums)来捕获其余部分,但这正是让我们陷入困境的所有剩余部分'_123_SPEED_X'.相反,我们说,"只要接下来的下划线没有Parameter,解析作为我的一部分Identifier,我们说,在pyparsing条款'_' + ~Parameter + Word(alphanums).由于我们假定我们可以有下划线+ WordButNotParameter重复任意数量的,我们换行表达式ZeroOrMore构造.(如果你总是期望在初始之后至少有下划线+ WordButNotParameter,你可以使用OneOrMore.)

最后,我们需要将初始Word和特殊下划线+ Word重复包装在一起,以便理解它们是连续的,不用空格分隔,因此我们将整个表达式包装在一个Combine构造中.这种方式'ABC _123_SPEED_X'会引发解析错误,但'ABC_123_SPEED_X'会正确解析.

还要注意我必须改变Keyword,Literal因为前者的方式太过微妙而且很快就会发怒.我不相信Keywords,也不能与他们匹配.