用于从python中的段落中提取句子的正则表达式

时间:2011-12-11 15:59:57

标签: python regex text-segmentation

我正在尝试使用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

使用上面的段落进行测试时,它会将输出与输入段落完全相同,但输出应如下所示 -

  

但在疟疾感染和败血症的情况下,整个身体的树突状细胞集中在提醒免疫系统,这阻止他们检测和应对任何新的感染

     

一种新型疫苗

正则表达式有什么问题吗?

3 个答案:

答案 0 :(得分:6)

Riccardo Murri的回答是正确的,但我想我会对这个话题有所了解。

关于PHP,有一个类似的问题:php sentence boundaries detection。我对这个问题的回答包括处理诸如“先生”,“太太”之类的例外情况。和“小”。我已经改编了正则表达式以使用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正确指出还有其他可能失败的例外情况。

答案 1 :(得分:2)

您作为示例发布的段落有第一句话 用双引号"括起来,结束报价立即出现 完全停止后:感染。“

你的正则表达式[.!?]\s{1,2}正在寻找一个句号后跟一个或 两个空格作为句子终止符,所以它不会捕获它。

可以通过允许选择来调整以应对这种情况 收尾报价:

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

但是,使用上面的正则表达式,您将删除结束引用 从句子。保持它稍微有点棘手,可以做到 使用后视断言:

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

但请注意,在很多情况下,基于正则表达式的分割器 失败,例如:

  • 缩写:“在A. B. Givental博士的作品中......” - 根据你的正则表达式,这将被错误地拆分 “Dr。”“A。”“B。”(您可以调整单字母大小写, 但除非您对其进行硬编码,否则无法检测缩写。)

  • 在句子中间使用感叹号: “......什么时候看见!Deshayes先生自己出现了......”

  • 使用多个引号和嵌套引号等

答案 2 :(得分: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 ]