2016-12-03 50 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)