2015-03-30 144 views
3

有沒有辦法將以下三個表達式合併爲一個正則表達式?結合三個正則表達式

name = re.sub(r'\s?\(\w+\)', '',name) # John Smith (ii) --> John Smith 
name = re.sub(r'\s?(Jr.|Sr.)$','', name, flags=re.I) # John Jr. --> John 
name = re.sub(r'".+"\s?', '', name) # Dwayne "The Rock" Johnson --> Dwayne Johnson 

回答

6

你可以只使用分組和管:

re.sub(r'(\s?\(\w+\))|(s?(Jr.|Sr.))|(".+"\s?)', '', name) 

Demo

1

如果你想獲得一個有效的(和工作的大部分時間)模式簡單地分離了你的模式管是一個壞主意。你必須重新考慮你想要對你的模式做什麼,並從開始重寫它。

p = re.compile(r'["(js](?:(?<=\b[js])r\.|(?<=\()\w+\)|(?<=")[^"]*")\s*', re.I) 
text = p.sub('', text).rstrip() 

這是要你以前寫過什麼重要的一個很好的機會:

  • 開始一個可選的字符模式\s?是緩慢的,因爲字符串中的每個位置必須有和沒有進行測試這個角色。因此,最好在最後捕獲可選的空白字符並修剪字符串。 (在所有情況下,即使您決定在開始時捕獲可選空白處,也需要修剪結果)
  • 查找帶引號的部分的模式是錯誤且效率低下的(工作時),因爲您使用點用一個貪婪的量詞,所以如果在同一行中有兩個引用部分(注意點不匹配換行符)之間的所有內容也將匹配。這是更好地使用否定字符類,不包含引號:"[^"]*"(注:這可以提高應對引號內的轉義引號)
  • 模式爲Jr.Sr.是假的太多,匹配一個字面.你需要逃避它。除 之外,該模式太不精確,因爲它不檢查之前是否有其他單詞字符。它將匹配例如以「蘇聯」結尾的句子。或者包含「jr」的任何子字符串。或「sr。」。 (是完全嚴格的,你必須檢查是否有空格或字符串的開始之前,但一個簡單的字邊界應該足夠了大部分的時間)

現在如何建立你的交替:

訂單可能很重要,特別是如果子模式不互相排斥。例如,如果您有子模式a+ba+,如果您編寫a+|a+b所有b前面有一個a永遠不會匹配,因爲第一個分支在之前成功。但就你的例子而言,並沒有這種問題。

順便說一句,如果你知道其中一個分支有更多的成功機會,把它放在交替的第一個位置。

您知道搜索到的子字符串以下列其中一個字符開頭:",(,j,s。在這種情況下,爲什麼不開始使用["(js]的模式,以避免測試字符串中所有位置的模式的每個分支。 然後,由於第一個字符已經被使用,所以您只需要檢查後面的哪些字符已經匹配每個分支。

通過這些小改進,您可以獲得更快的模式。