2014-11-22 62 views
4

我试图使用Pyparsing将像aaa:bbb(123)这样的字符串拆分为令牌。Pyparsing中的贪婪表达式

我可以用正则表达式来做到这一点,但我需要通过Pyparsing来做到这一点。

随着re的解决方案将是这样的:

>>> import re 
>>> string = 'aaa:bbb(123)' 
>>> regex = '(\S+):(\S+)\((\d+)\)' 
>>> re.match(regex, string).groups() 
('aaa', 'bbb', '123') 

这是不够清晰和简单。这里的关键点是\S+,意思是“除空格之外的所有东西”。现在

我会尝试用Pyparsing做到这一点:

>>> from pyparsing import Word, Suppress, nums, printables 
>>> expr = (
...  Word(printables, excludeChars=':') 
...  + Suppress(':') 
...  + Word(printables, excludeChars='(') 
...  + Suppress('(') 
...  + Word(nums) 
...  + Suppress(')') 
...) 
>>> expr.parseString(string).asList() 
['aaa', 'bbb', '123'] 

好吧,我们已经得到了相同的结果,但是这并不好看。我们设置excludeChars来使Pyparsing表达式停止在我们需要的位置,但这看起来不健壮。如果我们将在源字符串“排除”字符,相同的正则表达式将正常工作:

>>> string = 'a:aa:b(bb(123)' 
>>> re.match(regex, string).groups() 
('a:aa', 'b(bb', '123') 

而Pyparsing异常会明显突破:

>>> expr.parseString(string).asList() 
Traceback (most recent call last): 
    File "<input>", line 1, in <module> 
    File "/long/path/to/pyparsing.py", line 1111, in parseString 
    raise exc 
ParseException: Expected W:(0123...) (at char 7), (line:1, col:8) 

所以,问题是我们如何才能实现Pyparsing需要的逻辑?

回答

1

使用带前向断言正则表达式:

from pyparsing import Word, Suppress, Regex, nums, printables 

expr = (
    Word(printables, excludeChars=':') 
    + Suppress(':') 
    + Regex(r'\S+[^\(](?=\()') 
    + Suppress('(') 
    + Word(nums) 
    + Suppress(')') 
) 
1

与正则表达式,pyparsing纯粹是从左向右求,没有隐含的前瞻。

如果你想正则表达式的前瞻和回溯,你可以只使用一个正则表达式包含原来的重:

expr = Regex(r"(\S+):(\S+)\((\d+)\)") 
print expr.parseString(string).dump() 

['aaa:b(bb(123)'] 

但是,我看到这个只返回整场比赛作为一个单一的字符串。如果您希望能够访问各个组,你必须将其定义为命名组:

expr = Regex(r"(?P<field1>\S+):(?P<field2>\S+)\((?P<field3>\d+)\)") 
print expr.parseString(string).dump() 

['aaa:b(bb(123)'] 
- field1: aaa 
- field2: b(bb 
- field3: 123  

这表明,我认为一个良好的提升将是一个构造ARG添加到正则表达式返回结果作为所有重组的列表而不是字符串。