Что такое регулярное выражение для разбора отдельных предложений? - PullRequest
23 голосов
/ 20 декабря 2009

Я ищу хорошее регулярное выражение .NET, которое я могу использовать для анализа отдельных предложений из текста.

Он должен быть в состоянии разбить следующий блок текста ровно на шесть предложений:

Hello world! How are you? I am fine.
This is a difficult sentence because I use I.D.

Newlines should also be accepted. Numbers should not cause  
sentence breaks, like 1.23.

Это немного сложнее, чем я думал.

Любая помощь будет принята с благодарностью. Я собираюсь использовать это для обучения системы по известным текстам.

Ответы [ 6 ]

39 голосов
/ 20 декабря 2009

Попробуйте это @"(\S.+?[.!?])(?=\s+|$)":

string str=@"Hello world! How are you? I am fine. This is a difficult sentence because I use I.D.
Newlines should also be accepted. Numbers should not cause sentence breaks, like 1.23.";

Regex rx = new Regex(@"(\S.+?[.!?])(?=\s+|$)");
foreach (Match match in rx.Matches(str)) {
    int i = match.Index;
    Console.WriteLine(match.Value);
}

Результаты:

Hello world!
How are you?
I am fine.
This is a difficult sentence because I use I.D.
Newlines should also be accepted.
Numbers should not cause sentence breaks, like 1.23.

Для сложных, конечно, вам понадобится настоящий парсер, такой как SharpNLP или NLTK. Мой быстрый и грязный.

Вот информация SharpNLP и особенности:

SharpNLP - это коллекция натуральных инструменты языковой обработки, написанные на C #. В настоящее время это обеспечивает следующие инструменты НЛП:

  • разделитель предложений
  • токенизатор
  • тегер части речи
  • блок (используется для «поиска нерекурсивных синтаксических аннотаций, таких как фрагменты имен существительных»)
  • парсер
  • поиск имени
  • инструмент привязки
  • интерфейс к лексической базе данных WordNet
5 голосов
/ 20 декабря 2009

Невозможно использовать регулярные выражения для анализа естественного языка. Каков конец предложения? Период может происходить во многих местах (например, например). Вы должны использовать инструментарий синтаксического анализа на естественном языке, такой как OpenNLP или NLTK. К сожалению, в C # существует очень мало предложений. Поэтому вам, возможно, придется создать веб-сервис или иным образом ссылку на C #.

Обратите внимание, что в будущем это вызовет проблемы, если вы будете использовать точные пробелы, как в "I.D.". Вскоре вы найдете примеры, которые нарушают ваше регулярное выражение. Например, большинство людей ставят пробелы после своих данных.

В WP содержится превосходное резюме открытых и коммерческих предложений (http://en.wikipedia.org/wiki/Natural_language_processing_toolkits).. Мы использовали несколько из них. Это стоит усилий.

[Вы используете слово «поезд». Обычно это связано с машинным обучением (который является одним из подходов к НЛП и используется для разделения предложений). Действительно, наборы инструментов, которые я упоминал, включают машинное обучение. Я подозреваю, что это было не то, что вы имели в виду - скорее, вы бы развивали свое выражение посредством эвристики. Не!]

5 голосов
/ 20 декабря 2009
var str = @"Hello world! How are you? I am fine. This is a difficult sentence because I use I.D.
Newlines should also be accepted. Numbers should not cause sentence breaks, like 1.23.";

Regex.Split(str, @"(?<=[.?!])\s+").Dump();

Я проверял это в LINQPad.

2 голосов
/ 20 декабря 2009

Это на самом деле невозможно только с помощью регулярных выражений, если вы точно не знаете, какие у вас есть «сложные» токены, такие как «id», «Mr.» и т. Д. Например, сколько предложений «Пожалуйста, покажите свой идентификатор» Мистер Бонд.? Я не знаком с какими-либо реализациями C #, но я использовал токенайзер Punkt от NLTK. Вероятно, не должно быть слишком сложно для повторной реализации.

0 голосов
/ 05 января 2016

Большинство посоветовали использовать SharpNLP, и вам, вероятно, следует делать это, если только вы не хотите, чтобы в вашем отделе контроля качества проводился фестиваль ошибок.

Но так как вы, вероятно, находитесь под каким-то давлением. Вот еще одна попытка разобраться со словами типа «доктор» и "Х". Но он потерпит неудачу с предложением, оканчивающимся на «оно».

Привет, мир! Как твои дела? Я в порядке. Это сложное предложение потому что я использую И.Д. Новые строки также должны быть приняты. Числа не должны вызвать разрывы предложений, как 1.23. См. Доктор B или мистер FooBar для H. Pylori оценка в кардии.

    var result = new Regex(@"(\S.+?[.!?])(?=\s+|$)(?<!\s([A-Z]|[a-z]){1,3}.)").Split(input).Where(s => !String.IsNullOrWhiteSpace(s)).ToArray<string>();
    foreach (var match in result) 
    {
        Console.WriteLine(match);
    }
0 голосов
/ 27 декабря 2009

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

(?<Sentence>\S.+?(?<Terminator>[.!?]|\Z))(?=\s+|\Z)

Я использовал Expresso , чтобы придумать:

//  using System.Text.RegularExpressions;
/// <summary>
///  Regular expression built for C# on: Sun, Dec 27, 2009, 03:05:24 PM
///  Using Expresso Version: 3.0.3276, http://www.ultrapico.com
///  
///  A description of the regular expression:
///  
///  [Sentence]: A named capture group. [\S.+?(?<Terminator>[.!?]|\Z)]
///      \S.+?(?<Terminator>[.!?]|\Z)
///          Anything other than whitespace
///          Any character, one or more repetitions, as few as possible
///          [Terminator]: A named capture group. [[.!?]|\Z]
///              Select from 2 alternatives
///                  Any character in this class: [.!?]
///                  End of string or before new line at end of string
///  Match a suffix but exclude it from the capture. [\s+|\Z]
///      Select from 2 alternatives
///          Whitespace, one or more repetitions
///          End of string or before new line at end of string
///  
///
/// </summary>
public static Regex regex = new Regex(
      "(?<Sentence>\\S.+?(?<Terminator>[.!?]|\\Z))(?=\\s+|\\Z)",
    RegexOptions.CultureInvariant
    | RegexOptions.IgnorePatternWhitespace
    | RegexOptions.Compiled
    );


// This is the replacement string
public static string regexReplace = 
      "$& [${Day}-${Month}-${Year}]";


//// Replace the matched text in the InputText using the replacement pattern
// string result = regex.Replace(InputText,regexReplace);

//// Split the InputText wherever the regex matches
// string[] results = regex.Split(InputText);

//// Capture the first Match, if any, in the InputText
// Match m = regex.Match(InputText);

//// Capture all Matches in the InputText
// MatchCollection ms = regex.Matches(InputText);

//// Test to see if there is a match in the InputText
// bool IsMatch = regex.IsMatch(InputText);

//// Get the names of all the named and numbered capture groups
// string[] GroupNames = regex.GetGroupNames();

//// Get the numbers of all the named and numbered capture groups
// int[] GroupNumbers = regex.GetGroupNumbers();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...