Expresión regular para encontrar y eliminar palabras duplicadas.

Usando expresiones regulares en C #, ¿hay alguna manera de encontrar y eliminar palabras o símbolos duplicados en una cadena que contenga una variedad de palabras y símbolos?

Ex.

Cadena inicial de palabras:

“Me gusta el ambiente. El ambiente es bueno”.

Cadena deseada:

“Me gusta el medio ambiente. Es bueno”

Se han eliminado duplicados: “el”, “entorno”, “.”

Como han dicho otros, necesita más que una expresión regular para hacer un seguimiento de las palabras:

var words = new HashSet(); string text = "I like the environment. The environment is good."; text = Regex.Replace(text, "\\w+", m => words.Add(m.Value.ToUpperInvariant()) ? m.Value : String.Empty); 

Esto parece funcionar para mi

 (\b\S+\b)(?=.*\1) 

Coincide como tal

 manzana manzana naranja  
 naranja rojo azul verde naranja verde azul  
 piratas ninjas vaqueros ninjas piratas  

Bueno, Jeff me ha mostrado cómo usar la magia de las referencias internas en la expresión y el modificador global para hacer que esto suceda, por lo que mi respuesta original es inoperante. Todos deberían ir a votar por la respuesta de Jeff. Sin embargo, para la posteridad, observo que hay un pequeño problema de sensibilidad del motor de expresiones regulares en este, y si estuviera usando expresiones regulares con sabor a Perl, tendría que hacer esto:

 \b(\S+)\b(?=.*\b\1\b.*) 

en lugar de la respuesta de Jeff, porque la expresión regular de C # capturará efectivamente \b en \1 pero PCRE no.

Echa un vistazo a las referencias atrasadas:
http://msdn.microsoft.com/en-us/library/thwdfzxy(VS.71).aspx

Esta es una expresión regular que encontrará palabras duplicadas. Pero solo coincidirá con una palabra por partida. Así que tienes que usarlo más de una vez.

 new Regex( @"(.*)\b(\w+)\b(.*)(\2)(.*)", RegexOptions.IgnoreCase ); 

Por supuesto, esta no es la mejor solución (ver otras respuestas, que proponen no utilizar una expresión regular). Pero pediste una expresión regular – aquí está una. Tal vez solo la idea te ayude …

Las expresiones regulares serían una mala elección de “herramientas” para resolver este problema. Quizás lo siguiente podría funcionar:

 HashSet corpus = new HashSet(); char[] split = new char[] { ' ', '\t', '\r', '\n', '.', ';', ',', ':', ... }; foreach (string line in inputLines) { string[] parts = line.Split(split, StringSplitOptions.RemoveEmptyEntries); foreach (string part in parts) { corpus.Add(part.ToUpperInvariant()); } } // 'corpus' now contains all of the unique tokens 

EDITAR: este soy yo haciendo una gran suposición de que estás “lexing” para algún tipo de análisis como la búsqueda.

Regex no es adecuado para todo. Algo como tu problema cae en esa categoría. Le aconsejaría que utilice un analizador en su lugar.

Algunas personas, cuando se enfrentan a un problema, piensan “Lo sé, usaré expresiones regulares”. Ahora tienen dos problemas.

Consulte Cuándo no usar Regex en C # (o Java, C ++, etc.)

Por supuesto, el uso de una expresión regular para dividir la cadena en palabras puede ser un primer paso útil, sin embargo, String.Split () es claro y fácil de hacer todo lo que necesita.

No podrá usar expresiones regulares para este problema, porque las expresiones regulares solo coinciden con los idiomas regulares. El patrón que está intentando hacer coincidir es sensible al contexto y, por lo tanto, no es “regular”.

Afortunadamente, es bastante fácil escribir un analizador. Echa un vistazo al código de Per Erik Stendahl.

Como otros han señalado, esto es factible con referencias inversas. Consulte http://msdn.microsoft.com/nb-no/library/thwdfzxy(en-us).aspx para obtener detalles sobre cómo usar las referencias inversas en .Net.

Su problema particular para eliminar la puntuación también lo hace un poco más complicado, pero creo que el código en este sentido (el espacio en blanco no es significativo en esa expresión regular) debería hacer el truco:

 (\b\w+(?:\s+\w+)*)\s+\1 

No he probado la expresión regular, pero debe coincidir con una o más palabras separadas por espacios en blanco que se repiten. Tendrás que agregar un poco más de lógica para permitir la puntuación y así sucesivamente.