2012-12-06 30 views
27

我正在使用python和正則表達式進行一些文本規範化。我想用'你'代替所有'u'或'U'。 以下是我迄今所做的:Python re.sub():如何用'you'代替所有'u'或'U'

import re 
text = 'how are u? umberella u! u. U. [email protected] U# u ' 
print re.sub (' [u|U][s,.,?,!,W,#,@ (^a-zA-Z)]', ' you ', text) 

我得到的輸出是:

how are you you berella you you you you you you 

正如你所看到的問題是,「umberella」改爲「berella」。另外我想保留在'u'後出現的角色。例如,我想'你!'改爲'你!'。任何人都可以告訴我我做錯了什麼,寫出正則表達式的最佳方式是什麼?

回答

48

首先,爲什麼你的解決方案沒有工作。你混淆了很多概念。大多數是character class與其他人。在第一個字符類中,您使用|,它源於alternation。在字符類中,你不需要管道。只是列出你希望所有的字符(字符和範圍):

[Uu] 

或者乾脆寫u如果使用不區分大小寫的修改。如果你在那裏寫一個管道,字符類將實際上匹配你的主題字符串中的管道。

現在在第二個字符類中,您使用逗號來分隔您的角色,出於某種奇怪的原因。這也只是將逗號包含在可匹配的字符中。 sW可能應該是內置的字符類。然後逃脫他們!否則,它們只會與文字s和文字W相匹配。但是\W已經包含了你在那裏列出的所有內容,所以單獨使用\W(沒有方括號)就足夠了。而最後一部分(^a-zA-Z)也不起作用,因爲它只包含^,(,)以及所有字母到字符類中。否定語法僅適用於整個字符類,如[^a-zA-Z]

你真正想要的是斷言前面或後面沒有字母u。你可以使用lookarounds。優點是它們不會被包含在比賽中,因此不會被刪除:

r'(?<![a-zA-Z])[uU](?![a-zA-Z])' 

請注意,我使用了原始字符串。對於正則表達式來說,通常是很好的做法,以避免轉義序列的問題。

這些是否定的變換,以確保您的u之前或之後沒有字母字符。這與斷言周圍存在非字母字符(這與您所做的類似)非常重要,因爲後一種方法在字符串的開頭或結尾不起作用。

當然,你也可以從替換字符串中刪除周圍you的空間。

如果你不想更換u旁邊,是個數字,你可以很容易地包括數字到字符類:

r'(?<![a-zA-Z0-9])[uU](?![a-zA-Z0-9])' 

如果因爲某些原因,相鄰的下劃線也將取消其參賽資格的u爲了替換,你也可以包括它。但隨後的字符類與內置\w一致:

r'(?<!\w)[uU](?!\w)' 

,這是在這種情況下,相當於EarlGray的r'\b[uU]\b'。上面你提到

由於可以縮短所有這些,通過使用不區分大小寫的修改。以第一表達式作爲一個例子:根據自己的喜好

re.sub(r'(?<![a-z])u(?![a-z])', 'you', text, flags=re.I) 

re.sub(r'(?<![a-z])u(?![a-z])', 'you', text, flags=re.IGNORECASE) 

我建議你做一些通過我在這個答案鏈接幾次教程閱讀。這些解釋非常全面,應該給你一個很好的正則表達式的開頭,你可能遲早會遇到。

+2

您的回答非常好。謝謝! – user823743

+0

這是一個有趣的一般的技術,但我寧願使用\ b鍵匹配一個字打破 –

+2

@Sam我只是想確保使用'\ B'的意義是明確的(尤其是數字和下劃線包括在內)。 –

11

使用特殊字符\b,其中空字符串的開頭或在字的結尾匹配:因爲也有很多其他的標點符號

print re.sub(r'\b[uU]\b', 'you', text) 

空間是不是一個可靠的解決方案,所以一發明瞭抽象字符\b來表示單詞的開始或結束。

+2

除了' '\ b''是一樣的'' \ x08''。你需要逃避(''\\ b''或'r'\ b'')! – mata

+1

這是我在代碼中定義的「文字」您的代碼的輸出: 如何ü? umberella你! ü。 U. U @ U#u 所以你們中沒有一個人變成了你。 – user823743

+1

@ user823743是的,我在正則表達式之前忘記'r',因爲它是由Wooble編輯的(謝謝!)。 –

0

我想出了另一種可能的解決方案是:

re.sub(r'([uU]+(.)?\s)',' you ', text) 
相關問題