2011-08-19 41 views
5

我有以下文字:检索内部#{}文字

#{king} for a ##{day}, ##{fool} for a #{lifetime} 

而下面的(碎)的正则表达式:

[^#]#{[a-z]+} 

我想匹配所有#{字}而不是# #{words}(加倍'#'就像转义一样)。

今天我注意到,我有的正则表达式忽略了第一个单词(拒绝匹配#{king},但正确地忽略了## {day}和## {fool})。

>>> regex = re.compile("[^#]#{[a-z]+}") 
>>> regex.findall(string) 
[u' #{lifetime}'] 

有关如何改进当前正则表达式以适应我的需求的任何建议? 我想这个问题是[^#] ...

回答

6

你必须使用 “负向后断言”正确的正则表达式应该是这样的:

import re 
t = "#{king} for a ##{day}, ##{fool} for a #{lifetime}" 
re.findall(r'(?<!#)#{([a-z]+)}', t) 

返回

['king', 'lifetime'] 

说明:

(?<!prefix)pattern表达式匹配pattern只有当它不是由prefix preceeded。

+0

你的解决方案更好,我忘记了负面的后顾之忧。 – grep

+0

很酷的功能?这是蟒蛇正则表达式具体? –

+0

@Andrei,不,它似乎不是python特有的(根据[this site](http://www.regular-expressions.info/lookaround.html)),但他们说:“像JavaScript,Ruby和Tcl这样的风格可以做尽管它们确实支持lookahead,但根本不支持lookbehind。“ – MatToufoutu

0

试试这个:

re.compile('^#\{[\w]+\}') 
+1

你试过了吗?它仅匹配'#{king}',但不匹配'#{lifetime}'。 – hughdbrown

+0

我改正了它,它现在应该工作 – prince

2

使用回顾后建设:

>>> s='#{king} for a ##{day}, ##{fool} for a #{lifetime}' 
>>> r=re.compile(r'(?:^|(?<=[^#]))#{\w+}') 
>>> r.findall(s) 
['#{king}', '#{lifetime}'] 
>>> 
2
>>> regex = re.compile("(?:^|[^#])#{[a-z]+}") 
>>> regex.findall(string) 
['#{king}', ' #{lifetime}'] 
>>> 
+1

值得注意的是,这个解决方案的问题(不使用否定后置断言)是不适用于'#{king}#{blah}' - 'findall'返回非重叠匹配。 –

1

将其替换为(?:^|[^#])。就像你推断的那样,只有[^#]表示一个不是#的字符,这显然没有在行首。