3

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

当用上面的段落进行测试时,它给出的输出与输入段落完全相同,但输出应该看起来像 -

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

一种新型疫苗

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

4

3 回答 3

6

Riccardo Murri 的回答是正确的,但我想我会对该主题进行更多说明。

有一个关于 PHP 的类似问题:php sentence boundary detection。我对这个问题的回答包括处理“先生”、“夫人”等例外情况。和“小”。我已经调整了该正则表达式以与 Python 一起使用(这对后视有更多限制)。这是使用此新正则表达式的脚本的修改和测试版本:

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 正确指出了其他可能失败的例外情况。

于 2011-12-11T19:21:44.353 回答
2

您作为示例发布的段落的第一句用双引号括起来",结束引号紧跟在句号之后:感染。”

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

通过允许可选的结束引号,可以对其进行调整以应对这种情况:

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

但是,使用上述正则表达式,您将删除句子中的结尾引号。保持它稍微有点棘手,可以使用后向断言来完成:

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

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

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

  • 在句子中间使用感叹号: “......当,你瞧!M. Deshayes本人出现......”

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

于 2011-12-11T16:39:07.710 回答
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 ]
于 2011-12-11T16:37:39.837 回答