Это просто распознает язык, но не дает никаких функций НЛП. Мне просто нужно разделить текст на предложения, а это не позволяет.

ел бы разделить текст на предложения в PHP. В настоящее время я использую регулярное выражение, которое дает точность ~ 95% и хотелось бы улучшить его, используя лучший подход. Я видел инструменты NLP, которые делают это в Perl, Java и C, но не видел ничего подходящего для PHP. Знаете ли вы о таком инструменте?

 Noam19 февр. 2011 г., 08:45
"боль", потому что это медленнее, чем сказать С? Это регулярное выражение, которое я использую:preg_split("/(?<!\..)([\?\!\.]+)\s(?!.\.)/",$text,-1, PREG_SPLIT_DELIM_CAPTURE); Какой подход вы бы порекомендовали?
 SenG16 июн. 2015 г., 06:54
Будетgithub.com/bigwhoop/sentence-breaker библиотека какая-то польза для вас?
 fredley17 февр. 2011 г., 18:18
Какое регулярное выражение вы используете? НЛП в PHP звучит так, будто это причинит вам кучу боли.

Ответы на вопрос(7)

Незначительное улучшение на чужой работе:

$re = '/# Split sentences on whitespace between them.
(?<=                # Begin positive lookbehind.
  [.!?]             # Either an end of sentence punct,
| [.!?][\'"]        # or end of sentence punct and quote.
)                   # End positive lookbehind.
(?<!                # Begin negative lookbehind.
  Mr\.              # Skip either "Mr."
| Mrs\.             # or "Mrs.",
| Ms\.              # or "Ms.",
| Jr\.              # or "Jr.",
| Dr\.              # or "Dr.",
| Prof\.            # or "Prof.",
| Sr\.              # or "Sr.",
| \s[A-Z]\.              # or initials ex: "George W. Bush",
                    # or... (you get the idea).
)                   # End negative lookbehind.
\s+                 # Split on whitespace between sentences.
/ix';
$sentences = preg_split($re, $story, -1, PREG_SPLIT_NO_EMPTY);
 Kaii25 нояб. 2014 г., 17:05
Не могли бы вы объяснить, где вы на самом деле улучшились?

Создайте список сокращений, как это

$skip_array = array ( 

'Jr', 'Mr', 'Mrs', 'Ms', 'Dr', 'Prof', 'Sr' , etc.

Скомпилируйте их в выражение

$skip = '';
foreach($skip_array as $abbr) {
$skip = $skip . (empty($skip) ? '' : '|') . '\s{1}' . $abbr . '[.!?]';
}

Последний запустите этот preg_split, чтобы разбить на предложения.

$lines = preg_split ("/(?<!$skip)(?<=[.?!])\s+(?=[^a-z])/",
                     $txt, -1, PREG_SPLIT_NO_EMPTY);

И если вы обрабатываете HTML, следите за удалением тегов, которые устраняют пробел между предложениями.<p></p> Если у вас естьsituations.Like этоwhere.They склеить становится намного сложнее разобрать.

 user72322030 апр. 2011 г., 22:00
Взорваться просто дует строку на куски на основеdelimiter, Если вы говоритеexplode(" ", "Where are my suspenders?") The delimiter is"" пустое место. PHP будетexplode Ваша строка на куски, когда он сталкивается с пустым пространством. В этом случае в результате четыре слова, которые хранятся вarray какkeys [0-3].delimiter может быть что угодно,&, #, -, :и т.п.preg_split это более сложный взрыватель, который включает в себя рядmetacharacters, switches, functions and expressions, как в примере выше.

Я использовал это регулярное выражение:

preg_split('/(?<=[.?!])\s(?=[A-Z"\'])/', $text);

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

explode('.',$text);

потому что я решил, что скорость важнее точности.

ть использования серииexplode вызовы в цикле, используя.,!, и? как твоя игла Это было бы очень требовательно к памяти и процессору (как и большинство текстовых процессоров). У вас будет куча временных массивов и один мастер-массив со всеми найденными предложениями, численно проиндексированными в правильном порядке.

Кроме того, вы должны проверить общие исключения (такие как. В названиях, таких какГ-н. а такжеД-р), но с учетом того, что все находится в массиве, эти типы проверок не должны быть такими уж плохими.

Я не уверен, что это лучше, чем регулярное выражение с точки зрения скорости и масштабирования, но это стоило бы попробовать. Насколько велики эти блоки текста, которые вы хотите разбить на предложения?

 Noam29 апр. 2011 г., 10:31
Это не отвечает на мой вопрос, потому что я ищу библиотеку, которая делает это для меня. Но можете ли вы объяснить разницу между использованием explode и preg_split?
 Spudley30 апр. 2011 г., 22:12
@Noam:explode() разбивает на простое совпадение строк без каких-либо регулярных выражений. Смысл ответа в том, что для вашего случая использования это должно быть достаточно просто, чтобы сделать это без регулярных выражений; то есть просто взорваться на каждом общем знаке препинания. Однако я согласен, что он не отвечает на ваш вопрос и даже не отвечает на то, что вы пытаетесь задать. Вы стремитесь к точности, а это совсем не то, на чем он фокусируется. (но если бы вы выбрали этот подход, я быstrtok() быть лучшим решением, чемexplode() из-за нескольких знаков препинания)
Улучшенное решение регулярных выражений

Предполагая, что вы заботитесь об обработке:Mr. а такжеMrs. и т.д., тогда следующее единственное решение регулярных выражений работает довольно хорошо:

<?php // test.php Rev:20160820_1800
$split_sentences = '%(?#!php/i split_sentences Rev:20160820_1800)
    # Split sentences on whitespace between them.
    # See: http://stackoverflow.com/a/5844564/433790
    (?<=          # Sentence split location preceded by
      [.!?]       # either an end of sentence punct,
    | [.!?][\'"]  # or end of sentence punct and quote.
    )             # End positive lookbehind.
    (?<!          # But don\'t split after these:
      Mr\.        # Either "Mr."
    | Mrs\.       # Or "Mrs."
    | Ms\.        # Or "Ms."
    | Jr\.        # Or "Jr."
    | Dr\.        # Or "Dr."
    | Prof\.      # Or "Prof."
    | Sr\.        # Or "Sr."
    | T\.V\.A\.   # Or "T.V.A."
                 # Or... (you get the idea).
    )             # End negative lookbehind.
    \s+           # Split on whitespace between sentences,
    (?=\S)        # (but not at end of string).
    %xi';  // End $split_sentences.

$text = 'This is sentence one. Sentence two! Sentence thr'.
        'ee? Sentence "four". Sentence "five"! Sentence "'.
        'six"? Sentence "seven." Sentence \'eight!\' Dr. '.
        'Jones said: "Mrs. Smith you have a lovely daught'.
        'er!" The T.V.A. is a big project! '; // Note ws at end.

$sentences = preg_split($split_sentences, $text, -1, PREG_SPLIT_NO_EMPTY);
for ($i = 0; $i < count($sentences); ++$i) {
    printf("Sentence[%d] = [%s]\n", $i + 1, $sentences[$i]);
}
?>

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

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

Вот вывод из скрипта:

Sentence[1] = [This is sentence one.]
Sentence[2] = [Sentence two!]
Sentence[3] = [Sentence three?]
Sentence[4] = [Sentence "four".]
Sentence[5] = [Sentence "five"!]
Sentence[6] = [Sentence "six"?]
Sentence[7] = [Sentence "seven."]
Sentence[8] = [Sentence 'eight!']
Sentence[9] = [Dr. Jones said: "Mrs. Smith you have a lovely daughter!"]
Sentence[10] = [The T.V.A. is a big project!]

Основное решение регулярных выражений

Автор вопроса прокомментировал, что вышеуказанное решение"пропускает много вариантов" и не достаточно универсален. Я не уверен, что это значит, но суть вышеприведенного выражения настолько проста и понятна, насколько это возможно. Вот:

$re = '/(?<=[.!?]|[.!?][\'"])\s+(?=\S)/';
$sentences = preg_split($re, $text, -1, PREG_SPLIT_NO_EMPTY);

Обратите внимание, что оба решения правильно идентифицируют предложения, заканчивающиеся кавычкой после конечной пунктуации. Если вас не интересуют совпадающие предложения, заканчивающиеся кавычкой, регулярное выражение можно упростить до:/(?<=[.!?])\s+(?=\S)/.

Изменить: 20130820_1000 добавленнойT.V.A. (другое пунктуированное слово, которое нужно игнорировать) для регулярного выражения и проверки строки. (чтобы ответить на вопрос с комментариями PapyRef)

Изменить: 20130820_1800 Приведенный в порядок и переименован в регулярное выражение и добавил shebang. Также исправлены регулярные выражения для предотвращения разделения текста на конечные пробелы.

 David Meister05 дек. 2012 г., 12:28
@Noam - если вам нужно решение, основанное на машинном обучении, обновите свой вопрос.
 ridgerunner08 авг. 2011 г., 16:23
@ giorgio79: Да, если «элипсис» состоит из трех точек подряд. Если вы говорите об одном символе Unicode, представляющем elipsis, то этот символ Unicode должен быть добавлен в класс символов, чтобы это регулярное выражение работало.
 Noam04 мая 2011 г., 14:50
Это все еще очень прямой подход. Я ищу что-то общее, что было построено в процессе обучения. Ваше решение пропускает много вариантов.
 giorgio7908 авг. 2011 г., 10:55
Обнаруживает ли это многоточие? "..." в конце...
 LeMoussel19 авг. 2013 г., 09:33
С помощью этого расширенного решения регулярных выражений, как я могу обнаружить слово "T.V.A"? Я делаю это| [t|T]\.[v|V]\.[a|A]\. # or "T.V.A", но это не работает
 Noam19 февр. 2011 г., 08:56
Это просто распознает язык, но не дает никаких функций НЛП. Мне просто нужно разделить текст на предложения, а это не позволяет.

В результате я получаю 2 предложения:

Г-н Ж. Дюжарден регле са Т.В.A. en esp. uniquement

Правильным результатом должно быть предложение:Г-н Ж. Дюжарден регле са Т.В.А. en esp. uniquement

и с нашим тестовым пунктом

string sText = "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!\" The T.V.A. is a big project!";

Результат

index: 0 sentence: This is sentence one.
index: 22 sentence: Sentence two!
index: 36 sentence: Sentence three?
index: 52 sentence: Sentence "four".
index: 69 sentence: Sentence "five"!
index: 86 sentence: Sentence "six"?
index: 102 sentence: Sentence "seven.
index: 118 sentence: " Sentence 'eight!'
index: 136 sentence: ' Dr. Jones said: "Mrs. Smith you have a lovely daughter!
index: 193 sentence: " The T.V.
index: 203 sentence: A. is a big project!

Код C #:

                string sText = "Mr. J. Dujardin régle sa T.V.A. en esp. uniquement";
                Regex rx = new Regex(@"(\S.+?
                                       [.!?]               # Either an end of sentence punct,
                                       | [.!?]['""]         # or end of sentence punct and quote.
                                       )
                                       (?<!                 # Begin negative lookbehind.
                                          Mr.                   # Skip either Mr.
                                        | Mrs.                  # or Mrs.,
                                        | Ms.                   # or Ms.,
                                        | Jr.                   # or Jr.,
                                        | Dr.                   # or Dr.,
                                        | Prof.                 # or Prof.,
                                        | Sr.                   # or Sr.,
                                        | \s[A-Z].              # or initials ex: George W. Bush,
                                        | T\.V\.A\.             # or "T.V.A."
                                       )                    # End negative lookbehind.
                                       (?=|\s+|$)", 
                                       RegexOptions.CultureInvariant | RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled);
                foreach (Match match in rx.Matches(sText))
                {
                    Console.WriteLine("index: {0}  sentence: {1}", match.Index, match.Value);
                }

Ваш ответ на вопрос