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
定义),它会正确解析.
如何使这个解析器变得有点懒惰,并等到它与关键字匹配(而不是将整个字符串作为标识符啜饮并等待_
,而不存在.
谢谢.
[注意:这完全改写了我的问题; 我没有意识到真正的问题是什么]
我的答案是基于这个,因为你要做的是得到一个非贪婪的比赛.似乎这很难在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
因为前者的方式太过微妙而且很快就会发怒.我不相信Keyword
s,也不能与他们匹配.