2010-11-25 10 views
12

tengo una cadena muy grande (HTML) y en este HTML hay fichas particulares en los que todos ellos comienza con "#" y termina con "#"Detecta tokens particulares en una cadena. C#

simple Ej

<html> 
<body> 
     <p>Hi #Name#, You should come and see this #PLACE# - From #SenderName#</p> 
</body> 
</html> 

Necesito un código que detectará estos tokens y lo colocará en una lista. 0 - # Nombre # 1 - # Lugar # 2 - # # SenderName

sé que puedo usar expresiones regulares tal vez, de todos modos tienes algunas ideas para hacer eso?

Respuesta

8

sí se puede utilizar expresiones regulares.

string test = "Hi #Name#, You should come and see this #PLACE# - From #SenderName#"; 
Regex reg = new Regex(@"#\w+#"); 
foreach (Match match in reg.Matches(test)) 
{ 
    Console.WriteLine(match.Value); 
} 

Como es de suponer, \ w denota cualquier carácter alfanumérico. El + denota que puede aparecer 1 o más veces. Puede encontrar más información aquí msdn doc (para .Net 4. Encontrará otras versiones allí también).

2

Uso:

MatchCollection matches = Regex.Matches(mytext, @"#(\w+)#"); 

foreach(Match m in matches) 
{ 
    Console.WriteLine(m.Groups[1].Value); 
} 
+0

Debería funcionar si cambia la expresión regular a @ "# (. *) #" – T33C

3
foreach (Match m in Regex.Matches(input, @"#\w+#")) 
    Console.WriteLine("'{0}' found at index {1}.", m.Value, m.Index); 
+0

Cómo analizará 'Hola # Nombre # donde # LUGAR # más texto' correctamente. ¿Esto no analiza las palabras "fuera" de los hashes siempre que sea una sola palabra? ¿O me equivoco aquí? –

+0

Acabo de verificar: en su ejemplo, muestra "# Nombre #" y "# LUGAR #". Cuando se consideran varias coincidencias, cada una de ellas comienza después de que la anterior finaliza, es decir, después de que coincida con "# Nombre #", comienza a buscar una próxima coincidencia después del segundo signo hash. – VladV

+0

+1: Eso es perfecto. Veo por qué ahora, ya que el # es realmente "usado" por el primer partido, y por lo tanto no puede ser usado por el segundo también. Gracias por la iluminación. –

10

Puede probar:

// using System.Text.RegularExpressions; 
// pattern = any number of arbitrary characters between #. 
var pattern = @"#(.*?)#"; 
var matches = Regex.Matches(htmlString, pattern); 

foreach (Match m in matches) { 
    Console.WriteLine(m.Groups[1]); 
} 

respuesta inspirado en this cuestión de forma.

+2

+1 sí: se consideró usar la combinación no codiciosa. * También; aunque debería ser. +? –

+2

¿No se puede analizar un texto como este: 'Hola, # Nombre # donde # LUGAR # más texto', o he entendido mal cómo funciona RegEx. Puede que tampoco sea un problema válido para OP, por lo que es solo por mi propia curiosidad :) –

+0

Sí. Creo que fallará con 'Hola # Nombre # donde # LUGAR # más texto'. –

4

Una variante sin Regex si quieres:

var splitstring = myHtmlString.Split('#'); 
var tokens = new List<string>(); 
for(int i = 1; i < splitstring.Length; i+=2){ 
    tokens.Add(splitstring[i]); 
} 
+0

¿Por qué un voto negativo sobre esto? Procesa los resultados requeridos. Agradecería una razón del infractor. –

+1

funciona, le doy un +1 para compensar a la persona que ama demasiado la expresión regular. – tim

+0

@tim - he ...he ... gracias;) –

0

utilizar el método de Regex.Matches con un dibujo de algo así como

#[^#]+# para el patrón.

Cuál es posiblemente la manera más ingenua.

Esto podría entonces ser necesario ajustar si desea evitar la inclusión de caracteres las '#' en el partido de salida, posiblemente con un lookaround:

(?<=#)[^#]+(?=#)

(Un valor de coincidencia para esto sería ' hola' no '# # hola' - por lo que no tiene que hacer nada más recorte)

0

Esto le da una lista de las fichas según lo solicitado:

var tokens = new List<string>(); 
var matches = new Regex("(#.*?#)").Matches(html); 

foreach (Match m in matches) 
    tokens.Add(m.Groups[1].Value); 

Edit: Si no quiere quiere los caracteres de libra incluidos, simplemente muévalos fuera de los paréntesis en la cadena Regex (vea la respuesta de Pablo).

2

solución Naive:

var result = Regex 
    .Matches(html, @"\#([^\#.]*)\#") 
    .OfType<Match>() 
    .Select(x => x.Groups[1].Value) 
    .ToList(); 
2

probar esto

var result = html.Split('#') 
        .Select((s, i) => new {s, i}) 
        .Where(p => p.i%2 == 1) 
        .Select(t => t.s); 

Explicación:

línea 1 - dividimos el texto por el carácter '#'

línea 2 - seleccionamos una nuevo tipo anónimo, que incluye la posición de las cadenas en la matriz, y la cadena en sí

line3 - filtramos la lista de objetos anónimos a aquellos que tienen un valor de índice impar, seleccionando efectivamente 'cada' cadena, esto encaja con encontrar aquellas cadenas que están envueltas en el carácter hash, en lugar de aquellas fuera de

line4 = nos despojamos el indexador y devolver sólo la cadena del tipo anónimo

solución
+0

+1 por usar la sobrecarga 'Select' que le da el índice además del valor que creo que todos conocen. –

+0

Agradable y corto, pero ¿te importaría explicarlo un poco más? ¿sorbo? quizás usar variables "explicativas" lo haría más educativo para otros. – BerggreenDK

+1

explicación adicional –

1

LINQ:

 string s = @"<p>Hi #Name#, 
      You should come and see this #PLACE# - From #SenderName#</p>"; 

     var result = s.Split('#').Where((x, y) => y % 2 != 0).Select(x => x); 
+0

Agradable y breve, pero ¿te importaría explicarlo un poco más? x, y? quizás usar variables "explicativas" lo haría más educativo para otros. – BerggreenDK

+0

@BerggreenDK Por supuesto, el método 'Where' está sobrecargado. '(x, y)' es un par, donde 'x' es el elemento actual de la colección y' y' es el índice de este elemento. Sí, tienes razón, podría haber usado 'Where (item, index)' para una mejor legibilidad. Después de elegir solo cuerdas extrañas, porque son las que necesitamos. – nan

Cuestiones relacionadas