2009-11-17 33 views
40

En mi directorio personal tengo una carpeta drupal-6.14 que contiene la plataforma Drupal.expresión regular lookahead negativo

De este directorio utilizo el siguiente comando:

find drupal-6.14 -type f -iname '*' | grep -P 'drupal-6.14/(?!sites(?!/all|/default)).*' | xargs tar -czf drupal-6.14.tar.gz 

Lo que este comando hace es gzips la carpeta drupal-6.14, con exclusión de todas las subcarpetas de -6.14 Drupal/sites/excepto los sitios/todos y sitios/predeterminado, que incluye.

Mi pregunta es sobre la expresión regular:

grep -P 'drupal-6.14/(?!sites(?!/all|/default)).*' 

La expresión obras para excluir todas las carpetas que desea excluir, pero no entiendo muy bien por qué.

Es una tarea común el uso de expresiones regulares para

Encontrar todas las cadenas, excepto aquellos que No contienen x sub-patrón. O en otras palabras, negando un subpatrón.

I (creo) Entiendo que la estrategia general para resolver estos problemas es el uso de lookaheads negativos, pero nunca he entendido a un nivel satisfactorio cómo funcionan los aspectos positivos y negativos (adelante/atrás).

A lo largo de los años, he leído muchos sitios web sobre ellos. Los manuales de expresiones regulares de PHP y Python, otras páginas como http://www.regular-expressions.info/lookaround.html y demás, pero nunca he realmente tenía una sólida comprensión de ellos.

¿Podría alguien explicar, cómo funciona esto, y tal vez proporcionar algunos ejemplos similares que harían cosas similares?

- Modificar Uno:

En cuanto a la respuesta de Andomar: puede una búsqueda hacia delante doble negación puede expresar más sucintamente como una sola instrucción de búsqueda positiva hacia:

IE es:

'drupal-6.14/(?!sites(?!/all|/default)).*' 

equivalente a:

'drupal-6.14/(?=sites(?:/all|/default)).*' 

???

- Actualización Dos:

Según @andomar y @alan Moore - no se puede intercambiar lookahead doble negación de búsqueda positiva hacia delante.

Respuesta

84

Una búsqueda negativa hacia delante dice , en esta posición, la siguiente expresión regular no puede coincidir.

Tomemos un ejemplo simplificado:

a(?!b(?!c)) 

a  Match: (?!b) succeeds 
ac  Match: (?!b) succeeds 
ab  No match: (?!b(?!c)) fails 
abe No match: (?!b(?!c)) fails 
abc Match: (?!b(?!c)) succeeds 

El último ejemplo es una doble negación : Permite una b seguido de c. La anticipación negativa anidada se convierte en una anticipación positiva: debe estar presente el c.

En cada ejemplo, solo coincide el a. La búsqueda anticipada es solo una condición y no se agrega al texto coincidente.

+0

Si una búsqueda anticipada negativa anidada ("búsqueda negativa de doble negativo") puede convertirse en un avance positivo, ¿es posible establecer un equivalente en la forma de anticipación positiva? i.e: (a) ¿Cuál sería la forma de anticipación positiva de mi drupal de doble búsqueda negativa? "'drupal-6.14/(?! sites (?!/all |/default)). *'" example? Sería: 'drupal-6.14/(? = Sites/all | predeterminado). * ??? (b) ¿Cuál sería la forma positiva de anticipación de su doble búsqueda negativa "(!? B (?! C))" ejemplo? – themesandmodules

+0

eww. lo siento. primera vez que usamos los comentarios aquí, el formato es horrible. reafirmaré editando la pregunta. – themesandmodules

+0

@willieseabrook: No lo creo, solo parte de la anticipación es doblemente negativa, por lo que no puede reemplazar el todo con uno positivo – Andomar

12

Las miradas se pueden anidar.

Así que esta expresión coincide con "drupal-6.14 /", es decir no seguido de "sitios" que es no seguido por "/ all" o "/ default".

¿Confunde?Con otras palabras, podemos decir que coincide con "drupal-6.14 /", es decir no seguido de "sitios" menos que es seguido además por "/ all" o "/ default"

+0

Gracias por esto. Y * sí * Todavía lo encuentro confuso LOL. Creo que se cita "no seguido de sitios * a menos que * seguido de todos | predeterminado" sea bastante útil. – themesandmodules

1

Si revisa su expresión regular como esto:

drupal-6.14/(?=sites(?!/all|/default)).* 
      ^^ 

... entonces coincidirá con todas las entradas que contienen drupal-6.14/ seguido por sites seguido por que no sea/all o /default nada. Por ejemplo:

drupal-6.14/sites/foo 
drupal-6.14/sites/bar 
drupal-6.14/sitesfoo42 
drupal-6.14/sitesall 

Cambio ?= a ?! para que coincida con la expresión regular original, simplemente niega esos partidos:

drupal-6.14/(?!sites(?!/all|/default)).* 
      ^^ 

Por lo tanto, esto simplemente significa que drupal-6.14/ ahora no puede ser seguido por sites seguido por nada que no sea/all o /default. Así que ahora, estos entradas satisfará las expresiones regulares:

drupal-6.14/sites/all 
drupal-6.14/sites/default 
drupal-6.14/sites/all42 

Pero, lo que no puede ser obvio a partir de algunas de las otras respuestas (y posiblemente su pregunta) es que su expresión regular también permitirá otros entradas donde drupal-6.14/ es seguido por cualquier cosa que no sea sites también. Por ejemplo:

drupal-6.14/foo 
drupal-6.14/xsites 

Conclusión: lo tanto, su expresión regular básicamente dice que incluya todos los subdirectorios de drupal-6.14 excepto aquellos subdirectorios de sites cuyo nombre comienza con otra cosa que no sea all o default.