2009-12-20 23 views
22

Estoy buscando una buena expresión .NET regular que pueda usar para analizar oraciones individuales de un cuerpo de texto.¿Qué es una expresión regular para analizar oraciones individuales?

Debe ser capaz de analizar el siguiente bloque de texto en exactamente seis frases:

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. 

Esto está demostrando ser un poco más difícil de lo que pensaba en un principio.

Cualquier ayuda sería muy apreciada. Voy a usar esto para entrenar el sistema en cuerpos de texto conocidos.

+0

@Luke: Parecía que quería un salto de línea visible entre "causa" y "condena" en el texto de muestra, pero no estaba mostrando hacia arriba. Lo obligué a mostrar insertando dos espacios antes del salto de línea. Así es como querías que fuera, ¿no? –

+0

Sí, eres perfecto! Gracias por arreglar esto Tonto de mí (sigue siendo un novato). –

Respuesta

36

Prueba este @"(\S.+?[.!?])(?=\s+|$)":

string [email protected]"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); 
} 

Resultados:

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. 

Para los más complicados, por supuesto, necesitará un programa de análisis real como SharpNLP o NLTK. El mío es solo uno rápido y sucio.

Aquí es el SharpNLP información y características:

SharpNLP es una colección de herramientas naturales de procesamiento del lenguaje escrito en C# . Actualmente proporciona los siguientes herramientas de PNL:

  • un divisor frase
  • un tokenizer
  • un etiquetador parte de discurso
  • un chunker (utilizado para "encontrar anotaciones sintácticas no recursivos tales como trozos sintagma nominal ")
  • un analizador
  • un nombre del buscador
  • una herramienta de correferencia
  • una interfaz con la base de datos léxica WordNet
+3

+1 por señalarnos a SharpNLP que no había visto antes y puede ser muy útil. –

+0

Es mejor usar una aserción de preanálisis para '(?: \ S + | $)'. – Gumbo

+0

Gracias por la información de Gumbo, es mejor, pero tuve que agregar \ S en el frente, porque los espacios en blanco tienen que desnudarse en el lado izquierdo. – YOU

2

Esto no es realmente posible con sólo expresiones regulares, a menos que sepa exactamente qué fichas "difíciles" que tenga, como "id", "Sr." , etc. Por ejemplo, ¿cuántas oraciones es "Por favor muestre su identificación, Sr. Bond"? No estoy familiarizado con ninguna implementación de C#, pero he usado Punkt tokenizer de NLTK. Probablemente no debería ser demasiado difícil de implementar.

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

He probado esto en LINQPad.

+0

Gracias por probarlo. –

5

Es imposible usar expresiones regulares para analizar el lenguaje natural. ¿Cuál es el final de una oración? Un período puede ocurrir en muchos lugares (por ejemplo, por ejemplo). Debe utilizar un kit de herramientas de análisis de lenguaje natural como OpenNLP o NLTK. Desafortunadamente, hay muy pocas ofertas en C#. Por lo tanto, puede tener que crear un servicio web o vincularlo a C#.

Tenga en cuenta que causará problemas en el futuro si depende del espacio en blanco exacto como en "I.D.". Pronto encontrará ejemplos que rompen su expresión regular. Por ejemplo, la mayoría de las personas ponen espacios después de sus iniciales.

Hay un excelente resumen de ofertas abiertas y comerciales en WP (http://en.wikipedia.org/wiki/Natural_language_processing_toolkits). Hemos usado varios de ellos. Vale la pena el esfuerzo.

[Usa la palabra "tren". Esto se asocia normalmente con el aprendizaje automático (que es un enfoque de NLP y se ha utilizado para dividir oraciones). De hecho, los kits de herramientas que he mencionado incluyen aprendizaje automático. Sospecho que eso no era lo que querías decir, sino que desarrollarías tu expresión a través de la heurística. No]

+0

Gracias por esa información. Siempre estoy intrigado en el aspecto de aprendizaje automático de esto y este es un aspecto que me gustaría investigar. Para mi propósito actual, de hecho creo que el enfoque simple de expresiones regulares (donde no espero que estos casos extraños de los que hablas) esté bien. Sin embargo, probaré los marcos de los que hablas porque ya existen. –

0

que utilizan las sugerencias publicadas aquí y se acercó con la expresión regular que las costuras para lograr lo que quiero hacer:

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

Solía ​​Expresso para llegar a:

// 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

La mayoría ha aconsejado usar un SharpNLP y probablemente deba hacerlo a menos que desee que su departamento de control de calidad tenga un festival de errores.

Pero dado que probablemente se encuentre bajo algún tipo de presión. Aquí hay otro intento de tratar con palabras como "Dr." y "X." Pero, fallará con una oración que termina en "eso".

¡Hola, mundo! ¿Cómo estás? Estoy bien. Esta es una oración difícil porque uso I.D. Las nuevas líneas también deben ser aceptadas. Los números no deberían causar interrupciones de frase, como 1.23. Vea al Dr. B o al Sr. FooBar para la evaluación de H. pylori en el cardia.

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); 
    } 
Cuestiones relacionadas