2009-03-29 11 views
10

Originalmente era una pregunta que quería formular, pero al investigar los detalles de la pregunta encontré la solución y pensé que podría ser de interés para otros.Expresión regular que coincide entre comillas, que contiene citas escapadas

En Apache, la solicitud es completa entre comillas dobles y las comillas en el interior siempre se escapó con una barra invertida:

1.2.3.4 - - [15/Apr/2005:20:35:37 +0200] "GET /\" foo=bat\" HTTP/1.0" 400 299 "-" "-" "-" 

Estoy tratando de construir una expresión regular que coincide con todos los campos distintos. Mi solución actual siempre se detiene en la primera cita después de la GET/POST (en realidad sólo necesito todos los valores que incluyen el tamaño transferido):

^(\d+\.\d+\.\d+\.\d+)\s+[^\s]+\s+[^\s]+\s+\[(\d+)/([A-Za-z]+)/(\d+):(\d+):(\d+):(\d+)\s+\+\d+\]\s+"[^"]+"\s+(\d+)\s+(\d+|-) 

supongo que también proporcionaré mi solución de mi fuente PHP con comentarios y mejor formato:

$sPattern = ';^' . 
    # ip address: 1 
    '(\d+\.\d+\.\d+\.\d+)' . 
    # ident and user id 
    '\s+[^\s]+\s+[^\s]+\s+' . 
    # 2 day/3 month/4 year:5 hh:6 mm:7 ss +timezone 
    '\[(\d+)/([A-Za-z]+)/(\d+):(\d+):(\d+):(\d+)\s+\+\d+\]' . 
    # whitespace 
    '\s+' . 
    # request uri 
    '"[^"]+"' . 
    # whitespace 
    '\s+' . 
    # 8 status code 
    '(\d+)' . 
    # whitespace 
    '\s+' . 
    # 9 bytes sent 
    '(\d+|-)' . 
    # end of regex 
    ';'; 

el uso de este con un caso sencillo en el que la URL no contiene otras citas funciona bien:

1.2.3.4 - - [15/Apr/2005:20:35:37 +0200] "GET /\ foo=bat\ HTTP/1.0" 400 299 "-" "-" "-" 

Ahora trato de obtener soporte para ninguna, una o más apariciones de \" en él, pero no puedo encontrar una solución. Usando regexpal.com He ocurrió esto hasta ahora:

^(\d+\.\d+\.\d+\.\d+)\s+[^\s]+\s+[^\s]+\s+\[(\d+)/([A-Za-z]+)/(\d+):(\d+):(\d+):(\d+)\s+\+\d+\]\s+"(.|\\(?="))*" 

Esto es sólo la parte cambiada:

# request uri 
    '"(.|\\(?="))*"' . 

Sin embargo, es demasiado codicioso. Se come todo hasta el último ", cuando solo debería comer hasta el primer " no precedido por un \. También he intentado introducir el requisito de que no hay \ antes de la " que quiero, pero todavía se come al final de la cadena (Nota: he tenido que añadir extraños \ caracteres para hacer este trabajo en PHP):

# request uri 
    '"(.|\\(?="))*[^\\\\]"' . 
* ?::? Si se utiliza inmediatamente después de cualquiera de los cuantificadores , +, o {}, que hace que el cuantificador no expansivo (que coincide con el número mínimo de veces)

# request uri 
    '"(.|\\(?="))*?[^\\\\]"' . 

Pero entonces me di

La expresión regular completa:

^(\d+\.\d+\.\d+\.\d+)\s+[^\s]+\s+[^\s]+\s+\[(\d+)/([A-Za-z]+)/(\d+):(\d+):(\d+):(\d+)\s+\+\d+\]\s+"(.|\\(?="))*?[^\\]"\s+(\d+)\s+(\d+|-) 

actualización 5 ª mayo de 2009:

he descubierto un pequeño defecto en la expresión regular debido analizar millones de líneas: se rompe en las líneas que contienen el carácter de barra invertida justo antes de la doble citar. En otras palabras:

...\\" 

romperá la expresión regular. Apache no registrará ...\", pero siempre escapará a la barra diagonal inversa a \\, por lo que es seguro asumir que cuando hay dos caracteres de barra invertida antes de la comilla doble.

¿Alguien tiene una idea de cómo solucionar esto con la expresión regular?

recursos útiles: the JavaScript Regexp documentation at developer.mozilla.org y regexpal.com

Respuesta

26

Prueba esto:

"(?:[^\\"]+|\\.)*" 

Esta expresión regular coincide con un carácter de comillas dobles seguido por una secuencia de cualquiera de cualquier carácter que no sea \ y " o una secuencia escapado \α (donde α puede ser cualquier carácter) f ollowed por el personaje final de comillas dobles. El (?:expr) sintaxis es solo un grupo no capturable.

+2

¿Podría agregar algo más de información sobre su expresión regular para el beneficio de todos? Apenas logré entender lo que escribí ... gracias :) – mark

+5

(?: A | B) coincide con A o B. \\. coincide con una barra invertida que sigue a cualquier carácter, excepto la línea nueva. [^ \\ "] coincide con cualquier carácter excepto la barra diagonal inversa y comillas dobles. Poner todo junto hace exactamente lo que quieras, +1. –

+0

hermosa ... gracias hombre. –

Cuestiones relacionadas