2010-01-29 33 views
11

Mi entrada consiste en cadenas publicadas por el usuario.Regex: cómo obtener palabras de una cadena (C#)

Lo que quiero hacer es crear un diccionario con palabras y con qué frecuencia se han utilizado. Esto significa que quiero analizar una cadena, eliminar toda la basura y obtener una lista de palabras como salida.

Por ejemplo, dicen que la entrada es "#@[email protected] YOU'VE BEEN \***PWN3D*** ! :') !!!1einszwei drei !"

La salida que necesito es la lista:

  • "LOLOLOL"
  • "YOU'VE"
  • "BEEN"
  • "PWN3D"
  • "einszwei"
  • "drei"

No soy ningún héroe en expresiones regulares y se han de buscar en Google, pero mis costuras Google-kungfu a ser débiles y hellip;

¿Cómo pasaría de la entrada a la salida deseada?

+3

http://regular-expressions.info – Jason

Respuesta

18

expresión regular simple:

\w+

Esto coincide con una cadena de caracteres "palabra". Eso es casi lo que quiere.

Esto es un poco más precisa:

\w(?<!\d)[\w'-]*

Coincide con cualquier número de caracteres de palabra, asegurando que el primer carácter no era un dígito.

Éstos son mis partidos:

1 LOLOLOL
2 Has
3 SIDO
4 PWN3D
5 einszwei
6 drei

Ahora, eso es más como eso.

EDIT:
La razón de la mirada detrás negativo, es que algunos de los sabores de expresiones regulares compatibles con caracteres Unicode. Al usar [a-zA-Z] se perderían bastantes caracteres de "palabras" que sean deseables. Permitir \w y no permitir \d incluye todos los caracteres Unicode que posiblemente inicien una palabra en cualquier bloque de texto.

EDIT 2:
he encontrado una manera más concisa para conseguir el efecto negativo de la búsqueda hacia atrás: Clase de carácter negativo doble con una única exclusión negativo.

[^\W\d][\w'-]*(?<=\w)

Este es el mismo que el anterior, con la excepción de que también se asegura de que la palabra termina con un carácter de palabra. Y, por último, hay:

[^\W\d](\w|[-']{1,2}(?=\w))*

Asegurarse de que no hay más de dos no-palabras-caracteres en una fila. Aka, empareja "palabra arriba" pero no "palabra arriba", lo cual tiene sentido. Si desea que coincida con "palabra arriba", pero no "palabra arriba", puede cambiar 2 a 3.

+0

Muchas gracias, funciona como un encanto! :) – Led

+0

@Led: es posible que desee ver la Regex al final de la edición n. ° 2. Puede ser un poco más cercano a lo que estás buscando. –

+0

downvoted. Las palabras con el símbolo ''' se dividen en partes –

5

Debe considerar el procesamiento de lenguaje natural (NLP), no las expresiones regulares, y si se dirige a más de un idioma hablado, debe tenerlo en cuenta también. Como está utilizando C#, consulte el proyecto SharpNLP.

Editar: Este enfoque solo es necesario si le importa el contenido semántico de las palabras que intenta dividir.

+1

Gracias ¡mucho por la respuesta!:) Pero permítanos mantenerlo simple y decir que no me importa el lenguaje - - ¿Consideraré solo las palabras con un carácter opcionalmente '' 'y/o' - '? – Led

+1

@Mike Atlas, buen enlace. +1 – Gabe

+0

Si no le importa el idioma, ¿por qué no simplemente string.Replace() todos los caracteres que no desea y luego string.Split() en el carácter de espacio? No hay necesidad de expresiones regulares. –

2

No necesita necesariamente una expresión regular para esto, si tokenización es todo lo que está haciendo. Primero, puede desinfectar la cadena eliminando todos los caracteres que no sean letras, excepto los espacios, y luego haga un Split() en el carácter de espacio. Eso funcionará para casi todo, aunque las contracciones pueden ser difíciles. Eso debería comenzar por lo menos.

+0

Bien, entonces lo que quiero hacer es eliminar todos los caracteres inválidos, pero los caracteres 'y - tampoco son válidos SI no están entre caracteres alfabéticos. (en "word-up" el - es válido, en "palabra ----- arriba" el - los caracteres deben ser eliminados ...) – Led

+0

puedes poner allí un cheque que mirará para ver si el ''' o '-' está rodeado de letras y, si lo están, no lo eliminen. – Jason

0

Mi intuición no sería usar expresiones regulares, sino simplemente hacer un ciclo o dos.

iterar sobre cada caracter en la cadena, si no es un char válida, lo reemplazan con un espacio A continuación, utilice String.split() y dividida sobre espacios.

Los apóstrofes y los guiones pueden ser un poco más complicados para determinar si son caracteres basura o legita. Pero si está usando un bucle for para iterar sobre la cuerda, entonces mirar hacia adelante y hacia atrás del personaje actual debería ayudarlo.

Luego tendrá una lista de palabras: para cada una de estas palabras verifique si son válidas en su diccionario. Si quieres que esto sea rápido, realizar algún tipo de búsqueda binaria sería lo mejor. Pero solo para que funcione, sería más fácil comenzar con una búsqueda lineal.

EDIT: Solo mencioné lo del diccionario porque pensé que podría estar interesado solo en palabras legítimas, es decir, no "asdfasdf", pero ignore esa última afirmación si eso no es lo que necesita.

+0

no desea reemplazar caracteres no válidos con espacios. – Jason

2

Usando la siguiente

var pattern = new Regex(
    @"([^\W_\d]    # starting with a letter 
          # followed by a run of either... 
     ([^\W_\d] |   # more letters or 
     [-'\d](?=[^\W_\d]) # ', -, or digit followed by a letter 
    )* 
     [^\W_\d]    # and finishing with a letter 
    )", 
    RegexOptions.IgnorePatternWhitespace); 

var input = "#@[email protected] YOU'VE BEEN *PWN3D* ! :') !!!1einszwei drei foo--bar!"; 

foreach (Match m in pattern.Matches(input)) 
    Console.WriteLine("[{0}]", m.Groups[1].Value); 

produce una salida de

[LOLOLOL] 
[YOU'VE] 
[BEEN] 
[PWN3D] 
[einszwei] 
[drei] 
[foo] 
[bar]
+0

¿podría escribir una expresión regular normalmente? Me refiero a una sola línea sin caracteres adicionales –

+0

Buena explicación. – AnthonyVO

0

me escribió una extensión de cadena como esta:

private static string[] GetWords(string text) 
    { 
     List<string> lstreturn = new List<string>(); 
     List<string> lst = text.Split(new[] { ' ' }).ToList(); 
     foreach (string str in lst) 
     { 
      if (str.Trim() == "") 
      { 
       lstreturn.Add(str); 
      } 
     } 
     return lstreturn.ToArray(); 
    } 
+0

Esto no me parece una extensión. ¿Te estás perdiendo un 'esto'? –

Cuestiones relacionadas