2010-01-02 19 views
5

A raíz de una previous question en la que le pregunté:El uso de expresiones regulares para que coincida con la cadena entre dos cadenas, excluyendo las cadenas

¿Cómo puedo usar una expresión regular para que coincida con el texto que se encuentra entre dos cadenas, cuando esos dos cadenas ¿están ellas mismas encerradas otras dos cadenas, con cualquier cantidad de texto entre las cadenas internas y externas?

me dieron esta respuesta:

/outer-start.*?inner-start(.*?)inner-end.*?outer-end/ 

ahora me gustaría saber cómo excluir ciertas cadenas de texto entre las cadenas de cerramiento exteriores y las cadenas de cerramiento interior.

Por ejemplo, si tengo este texto:

externa en marcha un texto interno en marchatexto-que-i-quierointerior de gama poco más de texto externa -finalizar

Me gustaría que 'algunos textos' y 'algunos textos más' no contengan la palabra 'no deseado'.

En otras palabras, esto está bien:

exterior-START algunos querían texto interior empezartexto-que-i-quierointerior de gama algo más de texto deseado exterior de fin de

Pero esto no está bien:

externa en marcha algún texto no deseado interior empezartexto-que-i-quierointerior de gama poco más deseados de texto exterior de fin de

O a explicar con más detalle , la expresión entre delimitadores externos e internos en la respuesta anterior debe excluir la palabra 'no deseado'.

¿Esto es fácil de combinar usando expresiones regulares?

+0

¿Qué es exactamente estás tratando de hacer? – Gumbo

Respuesta

5

Reemplace el primero y el último (pero no el medio) .*? con (?:(?!unwanted).)*?. (Donde (?:...) es un grupo no capturable, y (?!...) es una búsqueda negativa)

Sin embargo, esto rápidamente termina con casos de esquina y advertencias en cualquier uso real (en lugar de ejemplo), y si usted pregunta qué realmente lo estás haciendo (con ejemplos reales, incluso si están simplificados, en lugar de ejemplos inventados), es probable que obtengas mejores respuestas.

+0

Esa es una solución mejor que la mía. –

0

Intente reemplazar el último. *? con: (?! (. * texto no deseado. *))

¿Funcionó?

+1

Si no está seguro (e incluso si cree que está seguro), debe probar su patrón localmente (o en un sitio como http://codepad.org/), que es por lo que las preguntas de expresiones regulares necesitan buenos ejemplos (ambos pasando y fallando). –

1

Puede reemplazar .*? con

([^u]|u[^n]|un[^w]|unw[^a]|unwa[^n]|unwan[^t]|unwant[^e]|unwante[^d])*? 

Ésta es una solución en la expresión regular "pura"; el lenguaje que está utilizando podría permitirle usar una construcción más elegante.

1

No puede hacer eso fácilmente con expresiones regulares, pero algunos sistemas como Perl tienen extensiones que lo hacen más fácil. Una forma es utilizar una afirmación negativa de preanálisis:

/outer-start(?:u(?!nwanted)|[^u])*?inner-start(.*?)inner-end.*?outer-end/ 

La clave es dividir el "no deseados" en ("u" No seguida de "Nwanted") o (no "u"). Eso permite que el patrón avance, pero aún así encontrará y rechazará todas las cadenas "no deseadas".

Sin embargo, la gente puede empezar a odiar tu código si haces gran parte de esto. ;)

2

Una mejor pregunta para hacerte a ti mismo que "¿cómo hago esto con expresiones regulares?" es "¿cómo puedo resolver este problema?". En otras palabras, no te obsesiones tratando de resolver un gran problema con expresiones regulares. Si puede resolver la mitad del problema con expresiones regulares, hágalo, luego resuelva la otra mitad con otra expresión regular o alguna otra técnica.

Por ejemplo, haga un pase sobre sus datos obteniendo todas las coincidencias, ignorando el texto no deseado (léase: obtenga resultados con y sin el texto no deseado). Luego, pase el conjunto reducido de datos y elimine los resultados que tienen el texto no deseado. Este tipo de solución es más fácil de escribir, más fácil de entender y más fácil de mantener a lo largo del tiempo. Y para cualquier problema que probablemente deba resolver con este enfoque, será lo suficientemente rápido.

0

Tola, resucitando esta pregunta porque tenía una solución de expresiones regulares bastante simple que no se mencionaba. Este problema es un caso clásico de la técnica explicada en esta pregunta a "regex-match a pattern, excluding..."

La idea es construir una alternancia (una serie de |), donde los lados izquierdo partido de lo que no quieren con el fin de conseguirlo fuera del camino ... entonces el último lado de | coincide con lo que queremos, y lo captura en el Grupo 1. Si se establece el Grupo 1, lo recuperas y tienes una coincidencia.

Entonces, ¿qué no queremos? En primer lugar, queremos eliminar todo el bloque externo si hay unwanted entre outer-start y inner-start. Puede hacerlo con:

outer-start(?:(?!inner-start).)*?unwanted.*?outer-end 

Esto será a la izquierda de la primera |. Coincide con un bloque exterior completo. En segundo lugar, queremos eliminar todo el bloque externo si hay unwanted entre inner-end y outer-end. Puede hacerlo con:

outer-start(?:(?!outer-end).)*?inner-end(?:(?!outer-end).)*?unwanted.*?outer-end 

Ésta será la media |.Parece un poco complicado porque queremos asegurarnos de que el "vago" *? no salta al final de un bloque en un bloque diferente.

En tercer lugar, unimos y capturamos lo que queremos. Esto es:

inner-start\s*(text-that-i-want)\s*inner-end 

Así que toda la expresión regular, en el modo libre separación, es decir:

(?xs) 
outer-start(?:(?!inner-start).)*?unwanted.*?outer-end # dont want this 
| # OR (also don't want that) 
outer-start(?:(?!outer-end).)*?inner-end(?:(?!outer-end).)*?unwanted.*?outer-end 
| # OR capture what we want 
inner-start\s*(text-that-i-want)\s*inner-end 

En this demo, mira las capturas del Grupo 1 de la derecha: Contiene lo que queremos, y solo para el bloque correcto

En Perl y PCRE (utilizado por ejemplo en PHP), ni siquiera tiene que mirar el Grupo 1: puede forzar a la expresión regular a omitir los dos bloques que no queremos. La expresión regular se convierte en:

(?xs) 
(?: # non-capture group: the things we don't want 
outer-start(?:(?!inner-start).)*?unwanted.*?outer-end # dont want this 
| # OR (also don't want that) 
outer-start(?:(?!outer-end).)*?inner-end(?:(?!outer-end).)*?unwanted.*?outer-end 
) 
(*SKIP)(*F) # we don't want this, so fail and skip 
| # OR capture what we want 
inner-start\s*\Ktext-that-i-want(?=\s*inner-end) 

See demo: coincide directamente lo que quiere.

La técnica se explica con todo detalle en la pregunta y en el artículo siguiente.

Referencia

Cuestiones relacionadas