2009-12-20 11 views
22

Szukam dobrego wyrażenia regularnego .NET, którego można użyć do analizowania poszczególnych zdań z treści tekstu.Co to jest wyrażenie regularne do analizowania poszczególnych zdań?

To powinno być zdolne do analizowania następujący blok tekstu na dokładnie sześć zdań:

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. 

Ten okazuje się trochę trudniejsze, niż początkowo sądzono.

Każda pomoc zostanie bardzo doceniona. Zamierzam użyć tego, by wyszkolić system na znanych ciałach tekstu.

+0

@Luke: Wyglądało to jak chciałeś widoczny podział wiersza między „przyczyna” i „kary” w przykładowym tekstem, ale nie pokazywał się. Zmusiłem to do pokazania, wstawiając dwie spacje przed podaniem linii. Tak właśnie wyglądało, prawda? –

+0

Tak, jesteś na miejscu! Dziękuję za naprawienie tego. Głupi mnie (nadal noob). –

Odpowiedz

36

Spróbuj @"(\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); 
} 

Wyniki:

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. 

Dla skomplikowanych, oczywiście, trzeba będzie prawdziwą parser jak SharpNLP lub NLTK. Mój jest szybki i brudny.

Oto SharpNLP informacji i cechy:

SharpNLP to zbiór narzędzi do przetwarzania naturalnych napisanych w języku C# . Obecnie dostarcza następujące narzędzia NLP:

  • rozgałęźnik zdanie
  • tokenizer
  • część-of-speech tagger
  • Chunker (stosowany w „znajdź nierekursywnych składniowe adnotacji takich jak rzeczownik kawałki Określenie ")
  • parser
  • nazwę znajdź
  • Narzędzie coreference
  • interfejs do WordNet leksykalne bazy
+3

+1 za skierowanie nas do SharpNLP, którego wcześniej nie widziałem i może być bardzo przydatny. –

+0

Lepiej użyj assertion look-ahead dla '(?: \ S + | $)'. – Gumbo

+0

Dzięki za informację Gumbo, tym lepiej, ale musiałem dodać \ S z przodu, ponieważ białe spacje muszą rozebrać na lewą stronę. – YOU

2

nie jest to możliwe tylko z wyrażeń regularnych, jeśli nie wiesz dokładnie, które „trudnych” tokeny masz, takie jak „id”, „Pan” itp. Na przykład ile zdań to "Proszę pokazać swój dowód tożsamości, panie Bond."? Nie znam żadnych implementacji C#, ale użyłem NLTK w wersji Punkt tokenizer. Prawdopodobnie nie powinno być zbyt trudne do ponownego wdrożenia.

5
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(); 

Testowałem to w LINQPad.

+0

Dzięki za wypróbowanie. –

5

Niemożliwe jest użycie wyrażeń regularnych do analizowania języka naturalnego. Jaki jest koniec zdania? Okres może wystąpić w wielu miejscach (np. Np.). Powinieneś użyć zestawu narzędzi do analizowania języka naturalnego, takich jak OpenNLP lub NLTK. Niestety istnieje bardzo niewiele, jeśli w ogóle, ofert w języku C#. Dlatego możesz utworzyć usługę sieciową lub w inny sposób połączyć się z C#.

Należy pamiętać, że spowoduje to problemy w przyszłości, jeśli polegamy na dokładnych odstępach, jak w "I.D.". Wkrótce znajdziesz przykłady, które łamią twoje wyrażenie regularne. Na przykład większość ludzi umieszcza spacje po swoich intonach.

Istnieje doskonałe podsumowanie ofert otwartych i komercyjnych w pakiecie WP (http://en.wikipedia.org/wiki/Natural_language_processing_toolkits). Użyliśmy kilku z nich. Warto wysiłku.

[Używasz słowa "pociąg". Zwykle jest to związane z uczeniem maszynowym (które jest jednym podejściem do NLP i było używane do dzielenia zdań). Rzeczywiście, wspomniane przeze mnie zestawy narzędzi obejmują uczenie maszynowe. Podejrzewam, że to nie było to, co miałeś na myśli - raczej, że wyewoluujesz swoją ekspresję poprzez heurystykę. Nie]

+0

Dziękuję za te informacje. Zawsze intryguje mnie aspekt uczenia maszynowego i jest to jeden aspekt, który chciałbym zbadać. W moim obecnym celu uważam, że proste podejście do wyrażenia regularnego (w którym nie oczekuję tych dziwnych przypadków, o których mówisz) jest w porządku. Jednak spróbuję ram, o których mówisz, ponieważ one już istnieją. –

0

Kiedyś propozycje zamieszczone tutaj i wpadł regex że szwy, aby osiągnąć to, co chcę zrobić:

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

użyłem Expresso wymyślić:

// 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(); 
0

Większość osób zaleca używanie SharpNLP i prawdopodobnie powinieneś to zrobić, chyba że chcesz, aby twój dział QA miał błąd.

Ale ponieważ prawdopodobnie masz pod presją. Oto kolejna próba radzenia sobie ze słowami takimi jak "Dr." i "X.". Ale nie uda się z wyrokiem kończącym się na "to".

Witaj, świecie! Jak się masz? Nic mi nie jest. To jest trudne zdanie ponieważ używam I.D. Newlines również powinny zostać zaakceptowane. Liczby nie powinny powodować przerwania zdania, jak 1,23. Zobacz Dr. B lub Mr. FooBar dla oceny H. pylori w cardii.

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); 
    } 
Powiązane problemy