Ответ 1
Попробуйте посмотреть Ruby wrapper вокруг Stanford Parser. Он имеет функцию getSentencesFromString().
Как вы принимаете абзац или большую сумму текста и разбиваете его на предложения (с использованием Ruby), принимая во внимание такие случаи, как г-н и д-р и U.S.A? (Предполагая, что вы просто помещаете предложения в массив массивов)
UPDATE: Одно из возможных решений, о которых я думал, включает использование тегатора части речи (POST) и классификатора для определения конца предложения:
Получение данных от мистера Джонса ощущало теплое солнце на его лице, когда он вышел на балкон своего летнего дома в Италии. Он был счастлив быть живым.
КЛАССИФИКАТОРОВ Г-н/ПЕРСОН Джонс/ЧЕЛОВЕК чувствовал /O/O тепло/O солнце /O включен/O его /O лицо/O как /O он/O ступил /O out/O на /O балкон/O/O his/O summer/O home/O in/O Italy/LOCATION./O He/O was/O happy/O to/O be/O alive/O./O
POST Г-н/ННП Джонс/ННП почувствовал /VBD the/DT warm/JJ sun/NN on/IN his/PRP $face/NN as/IN he/PRP stepped/VBD out/RP на /IN the/DT балкон /NN/IN его/PRP $summer/NN home/NN in/IN Italy./NNP Он /PRP был/VBD happy/JJ to/TO be/VB alive./IN
Можно ли считать, что, поскольку Италия - это место, период является допустимым окончанием предложения? С окончанием на "г-н" не будет других частей речи, можем ли мы предположить, что это не действительный период конца предложения? Это лучший ответ на мой вопрос?
Мысли?
Попробуйте посмотреть Ruby wrapper вокруг Stanford Parser. Он имеет функцию getSentencesFromString().
Просто, чтобы было ясно, нет простого решения. Это тема исследований НЛП как быстрый поиск Google.
Однако, похоже, что есть некоторые проекты с открытым исходным кодом, связанные с поддержкой обнаружения предложений NLP, я нашел следующий набор инструментов на основе Java:
Дополнительный комментарий: Проблема принятия решения о начале и конце предложений предложений также называется границей границ предложения (SBD) в обработка естественного языка.
Взгляните на разделитель предложений Python в NLTK (набор инструментов Natural Language Tool):
На основе следующей статьи:
Kiss, Tibor and Strunk, Jan (2006): Неконтролируемое обнаружение границ многоязычного предложения. Вычислительная лингвистика 32: 485-525.
Подход в работе довольно интересен. Они сводят проблему расщепления предложения к задаче определения того, насколько сильно слово связано с последующей пунктуацией. Перегрузка периодов после аббревиатур отвечает за большинство неоднозначных периодов, поэтому, если вы можете определить сокращения, вы можете с высокой вероятностью определить границы предложения.
Я тестировал этот инструмент неофициально и, кажется, давал хорошие результаты для разных (человеческих) языков.
Портирование его на Ruby было бы нетривиальным, но это могло бы дать вам некоторые идеи.
Похоже, этот рубиновый камень может сделать трюк.
Это сложная проблема, если вы действительно заботитесь о ее правильном использовании. Вы обнаружите, что пакеты парсеров NLP, вероятно, предоставляют эту функцию. Если вы хотите что-то быстрее, вам нужно будет дублировать некоторые из этих функций с помощью обученной вероятностной функции окна токенов (вы, вероятно, захотите подсчитать фид строки как токен, так как я могу отказаться от периода, если это конец абзаца).
Изменить: я рекомендую парсер Stanford, если вы можете использовать Java. У меня нет рекомендаций для других языков, но мне очень интересно узнать, что еще есть, что есть с открытым исходным кодом.
К сожалению, я не рубиновый парень, но, может быть, пример в perl заставит вас идти в правильном направлении. Используя несовместимый внешний вид для финишной пунктуации, некоторые частные случаи в не отставании, за которыми следует любое количество пробелов, за которым следует взгляд за большой буквы. Я уверен, что это не идеально, но я надеюсь, что это указывает на то, что вы в правильном направлении. Не знаете, как вы узнаете, действительно ли U.S.A в конце предложения...
#!/usr/bin/perl
$string = "Mr. Thompson is from the U.S.A. and is 75 years old. Dr. Bob is a dentist. This is a string that contains several sentances. For example this is one. Followed by another. Can it deal with a question? It sure can!";
my @sentances = split(/(?:(?<=\.|\!|\?)(?<!Mr\.|Dr\.)(?<!U\.S\.A\.)\s+(?=[A-Z]))/, $string);
for (@sentances) {
print $_."\n";
}
Может быть, попробуйте разделить его на период, за которым следует пробел, за которым следует буква в верхнем регистре? Я не уверен, как найти заглавные буквы, но это будет шаблон, на который я начну смотреть.
Изменить: Поиск заглавных букв с помощью Ruby.
Другое Редактировать:
Проверяйте препинание пунктуации, которая следует за словами, которые не начинаются с прописных букв.
Ответ доктора Мэннинга является наиболее подходящим, если вы рассматриваете JAVA (и Ruby тоже нелегко;)). Он здесь -
Существует разделитель предложений: edu.stanford.nlp.process.DocumentPreprocessor, Попробуйте выполнить команду: java edu.stanford.nlp.process.DocumentPreprocessor /u/nlp/data/lexparser/textDocument.txt
oneTokenizedSentencePerLine.txt. (Это делается через (хороший, но эвристический) FSM, так что это быстро; Вы не запуская вероятностный синтаксический анализатор.)
Но небольшое предложение, если мы изменим команду java edu.stanford.nlp.process.DocumentPreprocessor/u/nlp/data/lexparser/textDocument.txt > oneTokenizedSentencePerLine.txt TO java edu.stanford.nlp.process.DocumentPreprocessor -file/u/nlp/data/lexparser/textDocument.txt > oneTokenizedSentencePerLine.txt. Он будет работать нормально, так как вам нужно указать, какой файл будет представлен в качестве входных данных. So -file для текстового файла, -html для HTML и т.д.
Я не пробовал, но если английский - это единственный язык, который вас интересует, я предлагаю дать Lingua:: EN:: Readability взгляд.
Lingua:: EN:: Readability - это модуль Ruby, который вычисляет статистику по английскому тексту. Он может содержать подсчет слов, предложений и слогов. Он также может рассчитать несколько показателей удобочитаемости, таких как индекс тумана и уровень Flesch-Kincaid. Пакет включает в себя модуль Lingua:: EN:: Sentence, который разбивает английский текст на предложения, учитывающие аббревиатуры, и Lingua:: EN:: Syllable, который может угадывать количество слогов в письменном английском слове. Если доступен словарь произношения, он может искать количество слогов в словаре для большей точности
Бит, который вы хотите, находится в sentence.rb
следующим образом:
module Lingua
module EN
# The module Lingua::EN::Sentence takes English text, and attempts to split it
# up into sentences, respecting abbreviations.
module Sentence
EOS = "\001" # temporary end of sentence marker
Titles = [ 'jr', 'mr', 'mrs', 'ms', 'dr', 'prof', 'sr', 'sen', 'rep',
'rev', 'gov', 'atty', 'supt', 'det', 'rev', 'col','gen', 'lt',
'cmdr', 'adm', 'capt', 'sgt', 'cpl', 'maj' ]
Entities = [ 'dept', 'univ', 'uni', 'assn', 'bros', 'inc', 'ltd', 'co',
'corp', 'plc' ]
Months = [ 'jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul',
'aug', 'sep', 'oct', 'nov', 'dec', 'sept' ]
Days = [ 'mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun' ]
Misc = [ 'vs', 'etc', 'no', 'esp', 'cf' ]
Streets = [ 'ave', 'bld', 'blvd', 'cl', 'ct', 'cres', 'dr', 'rd', 'st' ]
@@abbreviations = Titles + Entities + Months + Days + Streets + Misc
# Split the passed text into individual sentences, trim these and return
# as an array. A sentence is marked by one of the punctuation marks ".", "?"
# or "!" followed by whitespace. Sequences of full stops (such as an
# ellipsis marker "..." and stops after a known abbreviation are ignored.
def Sentence.sentences(text)
text = text.dup
# initial split after punctuation - have to preserve trailing whitespace
# for the ellipsis correction next
# would be nicer to use look-behind and look-ahead assertions to skip
# ellipsis marks, but Ruby doesn't support look-behind
text.gsub!( /([\.?!](?:\"|\'|\)|\]|\})?)(\s+)/ ) { $1 << EOS << $2 }
# correct ellipsis marks and rows of stops
text.gsub!( /(\.\.\.*)#{EOS}/ ) { $1 }
# correct abbreviations
# TODO - precompile this regex?
text.gsub!( /(#{@@abbreviations.join("|")})\.#{EOS}/i ) { $1 << '.' }
# split on EOS marker, strip gets rid of trailing whitespace
text.split(EOS).map { | sentence | sentence.strip }
end
# add a list of abbreviations to the list that used to detect false
# sentence ends. Return the current list of abbreviations in use.
def Sentence.abbreviation(*abbreviations)
@@abbreviations += abbreviations
@@abbreviations
end
end
end
end
Согласитесь с принятым ответом, использование Stanford Core NLP не имеет проблем.
Однако в 2016 году существует некоторая несовместимость, взаимодействующая с Stanford Parser с более поздние версии ядра stanford nlp (у меня были проблемы с Stanford Core NLP v3.5).
Вот что я сделал, чтобы разобрать текст в предложениях с использованием Ruby-интерфейса с помощью NLP Stanford Core:
Установите Stanford CoreNLP gem - он все еще поддерживается и работает, он пытался найти NLP рубиновые камни, которые работа в последнее время:
gem install stanford-core-nlp
Затем следуйте инструкциям на readme для использования последней версии Stanford CoreNLP:
Использование последней версии Stanford CoreNLP (версия 3.5.0 на 31/10/2014) требуется несколько дополнительных шагов:
Загрузите Stanford CoreNLP версия 3.5.0 из http://nlp.stanford.edu/.
Поместите содержимое извлеченного архива в папку /bin/ драгоценный камень stanford-core-nlp (например, [...]/gems/stanford-core-nlp-0.x/bin/) или внутри местоположения каталога, настроенного настройкой StanfordCoreNLP.jar_path.
- Загрузите полную версию Stanford Tagger 3.5.0 из http://nlp.stanford.edu/.
- Создайте каталог с именем 'taggers' внутри/bin/папки жгута stanford-core-nlp (например, [...]/gems/stanford-core-nlp-0.x/bin/) или внутри каталога сконфигурированный настройкой параметра StanfordCoreNLP.jar_path.
- Поместите содержимое извлеченный архив внутри каталога taggers.
- Загрузите файл bridge.jar из https://github.com/louismullie/stanford-core-nlp.
- Поместите загруженный файл bridger.jar в папку /bin/ стэнфорд-сердечник-nlp (например, [...]/gems/stanford-core-nlp-0.x/bin/taggers/) или внутри каталога настраивается с помощью параметра StanfordCoreNLP.jar_path.
Затем код ruby для разделения текста на предложения:
require "stanford-core-nlp"
#I downloaded the StanfordCoreNLP to a custom path:
StanfordCoreNLP.jar_path = "/home/josh/stanford-corenlp-full-2014-10-31/"
StanfordCoreNLP.use :english
StanfordCoreNLP.model_files = {}
StanfordCoreNLP.default_jars = [
'joda-time.jar',
'xom.jar',
'stanford-corenlp-3.5.0.jar',
'stanford-corenlp-3.5.0-models.jar',
'jollyday.jar',
'bridge.jar'
]
pipeline = StanfordCoreNLP.load(:tokenize, :ssplit)
text = 'Mr. Josh Weir is writing some code. ' +
'I am Josh Weir Sr. my son may be Josh Weir Jr. etc. etc.'
text = StanfordCoreNLP::Annotation.new(text)
pipeline.annotate(text)
text.get(:sentences).each{|s| puts "sentence: " + s.to_s}
#output:
#sentence: Mr. Josh Weir is writing some code.
#sentence: I am Josh Weir Sr. my son may be Josh Weir Jr. etc. etc.
Я не парень из Ruby, но RegEx, который разбился на
^(Mr|Mrs|Ms|Mme|Sta|Sr|Sra|Dr|U\.S\.A)[\.\!\?\"] [A-Z]
было бы лучше, если у вас есть параграф (разделить на \r\n). Это предполагает, что ваши предложения правильно обрезаны.
Очевидно, это довольно уродливый RegEx. Как насчет ввода двух пробелов между предложениями
Разрыв в течение периода, за которым следует пробел, и заглавная буква не будет летать для таких титулов, как "Мистер Браун".
Периоды делают вещи трудными, но простой случай для обработки - восклицательные знаки и вопросительные знаки. Однако бывают случаи, когда это не сработает. то есть корпоративное имя Yahoo!
Ну, очевидно, paragraph.split('.')
не будет вырезать его
#split
будет принимать регулярное выражение в качестве ответа, поэтому вы можете попробовать использовать нулевую ширину для проверки слова, начинающегося с заглавной буквы. Конечно, это разделится на собственные имена, поэтому вам придется прибегнуть к регулярному выражению, подобному этому /(Mr\.|Mrs\.|U\.S\.A ...)
, которое было бы ужасно уродливым, если вы программно не создали регулярное выражение.
Я думаю, что это не всегда разрешимо, но вы можете разделить на основе "." (период с последующим и пустым пространством) и проверить, что слово до периода не находится в списке таких слов, как Mr, Dr, и др.
Но, конечно, ваш список может опустить некоторые слова, и в этом случае вы получите плохие результаты.
БЛАГОДАРЯ
Мне очень понравилось это обсуждение, поэтому я заинтересовался парсером. Я попробовал это, и я записал несколько заметок о том, как все работает с Ruby и Rails!
Попытка пойти с регулярным выражением была кошмаром.