2015-10-16 126 views
1

我試圖找到一個句子的一部分,在否定詞後面出現(例如,不要,不能,不),直到下一個標點符號並在句尾附加「_NOT」例如: 「我真的很喜歡土耳其,但不是西紅柿雞,因爲我過敏」變成 「我真的很喜歡土耳其,但沒有chicken_NOT with_NOT tomatoes_NOT,因爲我過敏」 。正則表達式匹配部分句子

最初我的方法是運行正則表達式,看起來是這樣的:

(dont|cant|not)(.*)[!?,.] 

讓我感興趣的句子的一部分,然後通過字去字,並附_NOT,然後運行str.replace(oldPartOfSentence,newPartOfSentence)

這幾乎可行,但搜索並不貪婪,如果我稍後有一個標點符號,它會找到比需要更長的部分。此外,如果我有一個否定詞,它不支持這種情況,但它後面沒有標點符號(那麼它應該將否定詞中的每個詞加上否定字符串到結尾)。

例如運行正則表達式的例句給

[('not', ' chicken with tomatoes')] 

但如果我有句號結尾,我得到:

[('not', " chicken with tomatoes, because I'm allergic")] 

我該如何解決這個問題,並在那裏這是一個更有效的解決方案嗎?例如,有沒有辦法更新正則表達式,通過re.sub()自動附加句子末尾的「_NOT」?

+4

變化'* '到'。*?'。 –

+0

謝謝,這解決了問題的第一部分。是否有可能使一些正則表達式也爲匹配字符串中的每個單詞添加「_NOT」? – Limon

+1

@Limonup:我不這麼認爲,不是直接。我最初認爲嘗試使用積極的背後的斷言,檢查不類似的單詞,並匹配在每個單詞跟隨它沒有干預標點符號,但至少對於Python來說,後面的斷言必須固定寬度,並嘗試向前搜索命中與不處理重疊匹配的搜索相關的問題,而需要省略匹配不相似的詞本身使得(AFAICT)也不切實際。你需要鏈接正則表達式調用。 – ShadowRanger

回答

1

根據Steven's comment,只需將.*更改爲.*?即可使其非貪婪。

你不能做替換用單一的正則表達式AFAICT(見my comment on the question的原因),但鏈式組替代將工作:

def add_nots(m): 
    notty, following = m.groups() 
    return notty + re.sub(r'(\S+)', r'\1_NOT', following) 

notted = re.sub(r'(dont|cant|not)(.*?)(?=[!?,.]|$)', add_nots, original_string) 

注:我做了一個額外的改變正則表達式使用積極的向前看斷言來避免捕獲終止標點符號(或行結束,這是一個改變;只有非貪婪修補程序給出的原始版本將不匹配,當notted行組件結束於字符串,而不是其中一個識別的標點符號),所以標點符號/行尾不需要被sub替換功能捕獲和再現。

另外,如果你打算這樣做了很多,與其他正則表達式穿插,你可能要預先編譯正則表達式對象,而不是依靠re緩存:

# One-time, up front, compile 
word_finder = re.compile(r'(\S+)') 
not_finder = re.compile(r'(dont|cant|not)(.*?)(?=[!?,.]|$)') 

def add_nots(m): 
    notty, following = m.groups() 
    return notty + word_finder.sub(r'\1_NOT', following) 

notted = not_finder.sub(add_nots, original_string) 
+0

注意:'add_nots' _could_是一個內聯'lambda',顯式調用'm.group(1)'和'm.group(2)',而不是解壓'm.groups()',然後使用命名的值(實際上,在測試時,這就是我的做法)。但爲了不寫不可讀的單行(特別是因爲這是SO,並且需要查看涉及的組件),我堅持使用獨立定義的命名函數,該函數將流分解爲邏輯組件,記錄名字。 – ShadowRanger

+0

謝謝,這是完美的。 – Limon