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

发布于 2024-12-20 21:50:29 字数 814 浏览 2 评论 0原文

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

当使用上面的段落进行测试时,它给出的输出与输入段落完全相同,但输出应该类似于 -

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

新型疫苗

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

I'm trying to extract a sentence from a paragraph using regular expressions in python.
Usually the code that I'm testing extracts the sentence correctly, but in the following paragraph the sentence does not get extracted correctly.

The paragraph:

"But in the case of malaria infections and sepsis, dendritic cells throughout the body are concentrated on alerting the immune system, which prevents them from detecting and responding to any new infections."
A new type of vaccine?

The code:

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

When tested with the above paragraph it gives output exactly as the input paragraph but the output should look like-

But in the case of malaria infections and sepsis, dendritic cells throughout the body are concentrated on alerting the immune system, which prevents them from detecting and responding to any new infections

A new type of vaccine

Is there anything wrong with the regular expression?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

平安喜乐 2024-12-27 21:50:29

里卡多·穆里(Riccardo Murri)的回答是正确的,但我想我应该对这个主题进行更多的阐述。

关于 PHP,有人提出了类似的问题:php 句子边界检测。我对这个问题的回答包括处理“先生”、“女士”等例外情况。和“小”。我已经调整了该正则表达式以与 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's answer is correct, but I thought I'd throw a bit more light on the subject.

There was a similar question asked with regard to PHP: php sentence boundaries detection. My answer to that question includes handling the exceptions such as "Mr.", "Mrs." and "Jr.". I've adapted that regex to work with Python, (which places more restrictions on lookbehinds). Here is a modified and tested version of your script which uses this new regex:

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

You can see how it handles the special cases and it is easy to add or remove them as required. It correctly parses your example paragraph. It also correctly parses the following test paragraph (which includes more special cases):

This is sentence one. Sentence two! Sentence three? Sentence "four". Sentence "five"! Sentence "six"? Sentence "seven." Sentence 'eight!' Dr. Jones said: "Mrs. Smith you have a lovely daughter!"

But note that there are other exceptions that can fail which Riccardo Murri has correctly pointed out.

纸伞微斜 2024-12-27 21:50:29

您作为示例发布的段落有其第一句话
用双引号 " 括起来,并且立即出现结束引号
句号后:感染。"

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

可以通过允许可选的选项来调整它以应对这种情况
结束引号:

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

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

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

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

  • 缩写:“In theworks of Dr. AB Givetal ...” --
    根据你的正则表达式,这将在之后被错误地分割
    “Dr.”“A.”“B.”(您可以调整单字母大小写,
    但你无法检测到缩写,除非你对其进行硬编码。)

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

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

The paragraph you've posted as an example has its first sentence
enclosed in double quotes ", and the closing quote comes immediately
after the full stop: infections."

Your regexp [.!?]\s{1,2} is looking for a period followed by one or
two spaces as sentence terminator, so it won't catch it.

It can be adjusted to cope with this case by allowing for optional
closing quotes:

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

However, with the above regexp you would be removing the end quote
from the sentence. Keeping it is slightly more tricky and can be done
using a look-behind assertion:

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

Note, however, that there are a lot of cases where a regexp-based splitter
fails, e.g.:

  • Abbreviations: "In the works of Dr. A. B. Givental ..." --
    according to your regexp, this will be incorrectly split after
    "Dr.", "A." and "B." (You can adjust the single-letter case,
    but you cannot detect an abbreviation unless you hard-code it.)

  • Use of exclamation marks in the middle of the sentence:
    "... when, lo and behold! M. Deshayes himself appeared..."

  • Use of multiple quote marks and nested quotes, etc.

尾戒 2024-12-27 21:50:29

是的,有问题。仅当分隔符后跟一个或两个空格,然后是一个大写字母时,您才会考虑分隔符,因此“一种新型疫苗?”的结尾。例如,句子不会被匹配。

我也不会对空格有太多限制,除非它是一个意图(文本可能格式不正确),因为例如“你好幸运男孩!你今天好吗?”不会被分裂。

我也不明白你的例子,为什么只有第一句话包含在 " 中?

无论如何:

>>> 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 ]

Yes, there is something wrong. You take the separator into account only if it is followed by one or two spaces and then a capital letter, so the end of "A new type of vaccine?" sentence won't get matched for example.

I would not be too restrictive about the spaces either, unless it is an intent (the text might not be well formated), because e.g. "Hello Lucky Boy!How are you today?" would not get splitted.

I also do not understand your example, why is only the first sentence is in enclosed in " ?

Anyway:

>>> 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',
     '']

You might also filter the empty sentences:

>>> NonemptyS = [ s for s in Senteces if s ]
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文