регулярное выражение для извлечения предложения из абзаца в Python - PullRequest
3 голосов
/ 11 декабря 2011

Я пытаюсь извлечь предложение из абзаца с помощью регулярных выражений в 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 ]

6 голосов
/ 11 декабря 2011

Риккардо Мурри ответил правильно, но я подумал, что смогу пролить немного света на эту тему.

Был задан похожий вопрос в отношении 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

Вы можете увидеть, как он обрабатывает особые случаи, и их легко добавлять или удалять по мере необходимости.Он правильно разбирает ваш пример абзаца.Он также правильно анализирует следующий тестовый параграф (который включает в себя больше особых случаев):

Это первое предложение.Приговор два!Приговор три?Приговор "четыре".Приговор "пять"!Приговор "шесть"?Приговор "семь".Приговор "восемь!"Д-р Джонс сказал: «Миссис Смит, у вас прекрасная дочь!»

Но учтите, что существуют и другие исключения, которые могут потерпеть неудачу, на что правильно указал Риккардо Мурри.

2 голосов
/ 11 декабря 2011

Абзац, который вы опубликовали в качестве примера, имеет первое предложение заключены в двойные кавычки ", и закрывающая кавычка приходит сразу после полной остановки: инфекции. "

Ваше регулярное выражение [.!?]\s{1,2} ищет период, за которым следует один или два пробела в качестве ограничителя предложения, поэтому он не поймает его.

Его можно отрегулировать, чтобы справиться с этим случаем, допуская закрывающие кавычки:

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

Однако, с помощью приведенного выше регулярного выражения вы удалили бы заключительную цитату из предложения. Держать это немного сложнее и может быть сделано используя косвенное утверждение:

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

Обратите внимание, однако, что во многих случаях разделитель на основе регулярных выражений не удается, например ::

  • Сокращения: «В работах доктора А. Б. Гивенталя ...» - согласно вашему регулярному выражению, это будет неправильно разделено после "Dr." , "A." и "B." (Вы можете настроить однобуквенный регистр, но вы не сможете обнаружить аббревиатуру, если не закодируете ее жестко.)

  • Использование восклицательных знаков в середине предложения: "... когда, о чудо! Сам господин Дешай появился ..."

  • Использование нескольких кавычек и вложенных кавычек и т. Д.

0 голосов
/ 11 декабря 2011

Да, что-то не так.Вы принимаете во внимание разделитель только в том случае, если за ним следуют один или два пробела, а затем заглавная буква, поэтому конец «вакцины нового типа?»Например, предложение не будет совпадать.

Я бы не стал слишком ограничивать пробелы, если только это не намерение (текст может быть плохо отформатирован), потому что, например, «Hello Lucky Boy! How areты сегодня?"не будет разделен.

Я также не понимаю ваш пример, почему только первое предложение заключено в "?

В любом случае:

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