我的答案是基于这个,因为你想要做的是得到一个非贪婪的匹配。看起来这在 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
当我们从交互式解释器运行它时,我们可以看到以下内容:
>>> Entry.parseString('ABC_123_SPEED_X 123')
(['ABC_123', 'SPEED_X', '123'], {})
请注意,这是一种妥协;因为我使用SkipTo
,Identifier
可以充满邪恶,令人作呕的字符,而不仅仅是alphanums
偶尔的下划线。
编辑:感谢 Paul McGuire,我们可以通过设置Identifier
以下内容来炮制一个真正优雅的解决方案:
Identifier = Combine(Word(alphanums) +
ZeroOrMore('_' + ~Parameter + Word(alphanums)))
让我们检查一下这是如何工作的。首先,忽略外部Combine
;我们稍后再谈。从Word(alphanums)
我们知道我们将得到'ABC'
引用字符串的一部分开始,'ABC_123_SPEED_X 123'
. 需要注意的是,在这种情况下,我们不允许“单词”包含下划线。我们将其单独构建到逻辑中。
接下来,我们需要在'_123'
不吸入的情况下捕获部分'_SPEED_X'
。让我们也跳过ZeroOrMore
这一点,稍后再返回。我们将下划线作为 . 开头Literal
,但我们可以使用 just 进行快捷方式'_'
,这将使我们成为前导下划线,但不是全部'_123'
。本能地,我们会放置另一个Word(alphanums)
来捕获其余的,但这正是消耗所有剩余的给我们带来麻烦的原因'_123_SPEED_X'
。相反,我们说,“只要下划线后面的不是,就将其Parameter
解析为 my 的一部分Identifier
。我们在 pyparsing 术语中将其声明为'_' + ~Parameter + Word(alphanums)
。由于我们假设我们可以有任意数量的下划线 + WordButNotParameter 重复,我们将其包装起来表达式 aZeroOrMore
构造。(如果您总是希望在首字母之后至少有下划线 + WordButNotParameter,您可以使用OneOrMore
.)
最后,我们需要将初始 Word 和特殊的下划线 + Word 重复包装在一起,以便理解它们是连续的,而不是由空格分隔,因此我们将整个表达式包装在一个Combine
构造中。这种方式'ABC _123_SPEED_X'
会引发解析错误,但'ABC_123_SPEED_X'
会正确解析。
另请注意,我必须更改Keyword
为,Literal
因为前者的方式太微妙且容易生气。我不信任Keyword
s,也无法与他们匹配。