2016-12-03 49 views
1

我定义意想不到的应用re.sub行为

s='f(x) has an occ of x but no y' 
def italicize_math(line): 
    p="(\W|^)(x|y|z|f|g|h)(\W|$)" 
    repl=r"\1<i>\2</i>\3" 
    return re.sub(p,repl,line) 

,并提出以下呼吁:

print(italicize_math(s) 

结果是

'<i>f</i>(x) has an occ of <i>x</i> but no <i>y</i>' 

这是不是我的预期。我想这个,而不是:

'<i>f</i>(<i>x</i>) has an occ of <i>x</i> but no <i>y</i>' 

任何人都可以告诉我为什么x的第一次出现没有被包含在“我”标签内?

+0

该解决方案还不错,但现在我知道我需要的东西,如单词边界更强大的通过\ B中提供不限制足够。我想将4x转换为4 x。换句话说,x旁边的4应该是一个边界。我会看看前瞻断言。 – user1741137

+0

由于下面的线索,我发现p ='(?<![A-Za-z])([xyzfgh])(?![A-Za-z])'和repl =' \ 1 '符合我的需求 – user1741137

回答

4

你似乎在试图匹配非字母数字字符(\W)当你真的想要一个字边界(\b):

>>> p=r"(\b)(x|y|z|f|g|h)(\b)" 
>>> re.sub(p,repl,s) 
'<i>f</i>(<i>x</i>) has an occ of <i>x</i> but no <i>y</i>' 

当然,(非字母数字 - 的原因是你的内容不匹配是因为\W在比赛中消耗了一个字符。所以像'f(x)'这样的字符串,当您匹配f时,您匹配(。由于(已经匹配,因此当您尝试匹配x时,它不会再匹配。相反,字边界不消耗任何字符。

3

由于组构造匹配字符串开头的位置,并且x会重叠前一个匹配。此外,第一和第三组是多余的,因为它们可以被字边界所替代;你可以使用一个字符类来组合字母。

p = r'\b([fghxyz])\b' 
repl = r'<i>\1</i>' 
1

像以前的答案提到,其因为(焦炭存在消耗匹配f当这样导致后续x失败的比赛。

旁边替换字边界\b,你也可以使用lookahead正则表达式,只是看一眼,并不会消耗前瞻内的任何匹配。因为它没有任何消耗,你不需要我得到了\3要么

p=r"(\W|^)(x|y|z|f|g|h)(?=\W|$)" 
repl=r"\1<i>\2</i>" 
re.sub(p,repl,line)