2008-10-07 21 views
5

Estoy escribiendo código para una página de resultados de búsqueda que debe resaltar los términos de búsqueda. Los términos suceden dentro de las celdas de la tabla (la aplicación se itera a través de celdas de filas de GridView), y estas celdas de la tabla pueden tener HTML.¿Qué regex coincidirá con el texto excluyendo lo que se encuentra dentro de las etiquetas HTML?

Actualmente, mi código es el siguiente (trozos relevantes se muestran a continuación):

const string highlightPattern = @"<span class=""Highlight"">$0</span>"; 
DataBoundLiteralControl litCustomerComments = (DataBoundLiteralControl)e.Row.Cells[CUSTOMERCOMMENTS_COLUMN].Controls[0]; 

// Turn "term1 term2" into "(term1|term2)" 
string spaceDelimited = txtTextFilter.Text.Trim(); 
string pipeDelimited = string.Join("|", spaceDelimited.Split(new[] {" "}, StringSplitOptions.RemoveEmptyEntries)); 
string searchPattern = "(" + pipeDelimited + ")"; 

// Highlight search terms in Customer - Comments column 
e.Row.Cells[CUSTOMERCOMMENTS_COLUMN].Text = Regex.Replace(litCustomerComments.Text, searchPattern, highlightPattern, RegexOptions.IgnoreCase); 

Sorprendentemente funciona. Pero, a veces el texto que estoy coincidente en es HTML que tiene este aspecto:

<span class="CustomerName">Fred</span> was a classy individual. 

Y si la búsqueda de la "clase" Quiero que el código más destacado para envolver la "clase" en "clase", pero por supuesto que no ¡el atributo HTML "clase" que está ahí! Si busca "Fred", eso debe resaltarse.

Entonces, ¿qué es una buena expresión regular que se asegurará de que las coincidencias ocurran solo FUERA de las etiquetas html? No tiene que ser súper duro. Simplemente me aseguro de que la coincidencia no esté entre < y> funcionaría bien.

+1

Si alguien ha buscado a Fred en su ejemplo, ¿debería estar resaltado? –

+0

Sí. Gracias por preguntar. Buena pregunta. Editaré la pregunta. – Chris

Respuesta

11

Esta expresión regular debe hacer el trabajo: (?<!<[^>]*)(regex you want to check: Fred|span) Comprueba que es imposible hacer coincidir la expresión regular <[^>]* yendo hacia atrás a partir de una cadena coincidente.

código modificado a continuación:

const string notInsideBracketsRegex = @"(?<!<[^>]*)"; 
const string highlightPattern = @"<span class=""Highlight"">$0</span>"; 
DataBoundLiteralControl litCustomerComments = (DataBoundLiteralControl)e.Row.Cells[CUSTOMERCOMMENTS_COLUMN].Controls[0]; 

// Turn "term1 term2" into "(term1|term2)" 
string spaceDelimited = txtTextFilter.Text.Trim(); 
string pipeDelimited = string.Join("|", spaceDelimited.Split(new[] {" "}, StringSplitOptions.RemoveEmptyEntries)); 
string searchPattern = "(" + pipeDelimited + ")"; 
searchPattern = notInsideBracketsRegex + searchPattern; 

// Highlight search terms in Customer - Comments column 
e.Row.Cells[CUSTOMERCOMMENTS_COLUMN].Text = Regex.Replace(litCustomerComments.Text, searchPattern, highlightPattern, RegexOptions.IgnoreCase); 
+0

Encontrado a través de Google, ayudó mucho, ¡gracias! :) – Teekin

+0

¡Muchas gracias! ¡Salvaste mi día! :) – podeig

+2

Este es un gran pedazo de código. Mereces mucho más votos de los que tienes. Muchas gracias. – draconis

2

Puede usar una expresión regular con grupos de balanceo y referencias inversas, pero le recomiendo encarecidamente que utilice un parser aquí.

0

Hmm, no soy un programador de C#, así que no sé el sabor de la expresión regular que utiliza, pero (?! <. +?>) Debería ignorar cualquier cosa dentro de las etiquetas. Te obligará a usar & # 60 & # 62 en tu código HTML, pero deberías estar haciendo eso de todos modos.

+0

Para que coincida con "clase" como describí en mi ejemplo, ¿dónde iría la palabra "clase" en su expresión regular? No entiendo cómo usar tu expresión regular. Por sí solo, parece coincidir con cada posición char en la frase completa. – Chris

+0

La expresión regular "(?! <.+?>)" es solo un lookahead negativo; dice, "desde esta posición, no estamos mirando algo que se parece vagamente a una etiqueta". No coincidirá con nada, ni impedirá que coincida con nada, dentro de una etiqueta o fuera. –

0

Escribir una expresión regular que puede manejar las secciones CDATA va a ser duro. Ya no puede suponer que> cierra una etiqueta.

Por ejemplo, "<span class="CustomerName>Fred.</span> is a good customer (<![CDATA[ >10000$ ]]>)"

La solución es (como se señaló anteriormente) un analizador sintáctico. Son mucho mejores para lidiar con el tipo de desastre que encuentras en un CDATA. La verificación hacia atrás de Madgnome no se puede utilizar para encontrar el <![CDATA de ]]>, ya que una sección de CDATA puede incluir el literal <![CDATA.

+0

Buen punto, no he pensado en eso. –

+0

Sé que la solución no es perfecta, pero sopesando todos los altibajos, es la mejor que he encontrado hasta ahora. – Chris

Cuestiones relacionadas