2011-12-11 51 views
3

我試圖從使用python中的正則表達式的段落中提取句子。
通常,我正在測試的代碼正確地提取了該語句,但是在下面的段落中該句子沒有正確提取。正則表達式從python中的段落中提取句子

段落:

「但是,在瘧疾感染和敗血症,樹突狀細胞在整個身體都集中在提醒免疫系統,以防止它們從檢測和響應任何新的感染的情況下,」 一種新型疫苗?

代碼:

def splitParagraphIntoSentences(paragraph): 

import re 

sentenceEnders = re.compile('[.!?][\s]{1,2}(?=[A-Z])') 
sentenceList = sentenceEnders.split(paragraph) 
return sentenceList 
if __name__ == '__main__': 
    f = open("bs.txt", 'r') 
    text = f.read() 
    mylist = [] 
    sentences = splitParagraphIntoSentences(text) 
    for s in sentences: 
     mylist.append(s.strip()) 
     for i in mylist: 
      print i 

當與前款測試它到底給輸出與輸入段落,但輸出看起來應該喜歡 -

但在瘧疾感染的情況下,和敗血症,整個身體的樹突細胞被集中在提醒免疫系統,以防止它們從檢測和響應任何新的感染

一種新型疫苗

正則表達式有什麼問題嗎?

+2

至少縮進代碼正確... – rubik

回答

2

您發佈作爲一個例子段落有雙引號括起來"它的第一句話 和關閉的引號來IMM在完全停止之後完全地 :感染。「

您的正則表達式[.!?]\s{1,2}正在尋找一段時間後跟一個或 兩個空格作爲句子終止符,因此它不會捕獲它。

它可以調整通過允許可選 引號,這種情況下,以應付:

sentenceEnders = re.compile(r'''[.!?]['"]?\s{1,2}(?=[A-Z])''') 

然而,你會從刑期中除去年底報價 上述正則表達式。保持它稍微棘手,可以使用向後看斷言完成 :

sentenceEnders = re.compile(r'''(?<=[.!?]['"\s])\s*(?=[A-Z])''') 

但是請注意,有很多情況下,其中一個基於正則表達式分離器 失敗,例如:

  • 縮寫:「在AB Givental博士的作品......」 - 根據你的正則表達式,這將是錯誤的之後 「博士」分裂「A.」「B.」(你可以調整單個字母的大小寫, 但你無法檢測的縮寫,除非你硬編碼。)

  • 在句子中使用感嘆號: 」 ......當,你瞧!M. DESHAYES自己出現了......」

  • 使用多個引號和嵌套報價等

+0

謝謝。在處理你提到的特殊情況時,你能否給我一些關於使用什麼方法或過程的建議。一點提示將會有很大幫助。 – martan

+0

@martan你可以看看PERL模塊的實現[Text :: Sentence](http://cpansearch.perl.org/src/AWRIGLEY/HTML-Summary-0.017/lib/Text/Sentence.pm)和[Lingua :: EN :: Sentence](http://cpansearch.perl.org/src/SHLOMOY/Lingua-EN-Sentence-0.25/lib/Lingua/EN/Sentence.pm),但我的觀點是,無論你的正則表達式如何精細化,總是處於角落的情況。 –

+0

非常感謝。我一定會研究這些模塊 – martan

0

是的,有什麼問題。只有在後面跟着一個或兩個空格,然後是大寫字母時,你纔會考慮分隔符,那麼「新型疫苗?」的結尾呢?例如,句子不會匹配。

我不會限制太多關於空間或者,除非它是一個意圖(文字可能不能很好地格式化),因爲如「你好,幸運的男孩,你今天好嗎?」不會被分割。

我也搞不懂你的榜樣,爲什麼只在封閉在「

反正第一句話:

>>> Text="""But in the case of malaria infections, dendritic cells and stuff. 
      A new type of vaccine? My uncle! 
     """ 
>>> Sentences = re.split('[?!.][\s]*',Text) 
>>> Sentences 
    ['But in the case of malaria infections, dendritic cells and stuff', 
    'A new type of vaccine', 
    'My uncle', 
    ''] 

您還可以過濾空的句子:

>>> NonemptyS = [ s for s in Senteces if s ] 
+0

段落的尾部將_always_包含在're.split'的返回值中,而不管實際的正則表達式是什麼。 –

5

裏卡爾多·穆裏的答案是正確的,但我想我會扔對這個小組有更多的瞭解JECT。

有一個類似的問題關於PHP:php sentence boundaries detection。我對這個問題的回答包括處理例如「先生」,「夫人」和「Jr.」。我已經調整了這個正則表達式來與Python一起工作(這對於lookbehinds有更多的限制)。這裏是你的腳本的修改和測試版本,它使用這個新的正則表達式:

def splitParagraphIntoSentences(paragraph): 
    import re 
    sentenceEnders = re.compile(r""" 
     # Split sentences on whitespace between them. 
     (?:    # Group for two positive lookbehinds. 
      (?<=[.!?])  # Either an end of sentence punct, 
     | (?<=[.!?]['"]) # or end of sentence punct and quote. 
     )     # End group of two positive lookbehinds. 
     (?<! Mr\. ) # Don't end sentence on "Mr." 
     (?<! Mrs\. ) # Don't end sentence on "Mrs." 
     (?<! Jr\. ) # Don't end sentence on "Jr." 
     (?<! Dr\. ) # Don't end sentence on "Dr." 
     (?<! Prof\.) # Don't end sentence on "Prof." 
     (?<! Sr\. ) # Don't end sentence on "Sr." 
     \s+    # Split on whitespace between sentences. 
     """, 
     re.IGNORECASE | re.VERBOSE) 
    sentenceList = sentenceEnders.split(paragraph) 
    return sentenceList 

if __name__ == '__main__': 
    f = open("bs.txt", 'r') 
    text = f.read() 
    mylist = [] 
    sentences = splitParagraphIntoSentences(text) 
    for s in sentences: 
     mylist.append(s.strip()) 
    for i in mylist: 
     print i 

你可以看到它是如何處理的特殊情況下,它是很容易根據需要添加或刪除它們。它正確地分析您的示例段落。它也正確地解析了以下測試段落(其中包括更多特殊情況):

這是句子一。第二句話!第三句話?句子「四」。句子「五」!句子「六」?句子「七」。句子'八'!瓊斯博士說:「史密斯夫人,你有一個可愛的女兒!」

但請注意,還有其他例外可能會失敗,Riccardo Murri已經正確指出。

相關問題