Questa era in origine una domanda che volevo porre, ma mentre ricercavo i dettagli per la domanda, ho trovato la soluzione e ho pensato che potesse interessare agli altri.Espressione regolare che corrisponde tra virgolette, contenente citazioni di escape
In Apache, la richiesta di piena è tra virgolette e le eventuali citazioni all'interno sono sempre cavata con un backslash:
1.2.3.4 - - [15/Apr/2005:20:35:37 +0200] "GET /\" foo=bat\" HTTP/1.0" 400 299 "-" "-" "-"
Sto cercando di costruire un'espressione regolare che corrisponde a tutti i campi distinti. La mia soluzione attuale si ferma sempre al primo preventivo dopo la GET
/POST
(in realtà ho solo bisogno di tutti i valori tra cui la dimensione trasferito):
^(\d+\.\d+\.\d+\.\d+)\s+[^\s]+\s+[^\s]+\s+\[(\d+)/([A-Za-z]+)/(\d+):(\d+):(\d+):(\d+)\s+\+\d+\]\s+"[^"]+"\s+(\d+)\s+(\d+|-)
Credo che andrò anche fornire la mia soluzione dalla mia sorgente PHP con i commenti e la formattazione meglio:
$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
';';
Utilizzando questo con un semplice caso in cui l'URL non contiene altre citazioni funziona bene:
1.2.3.4 - - [15/Apr/2005:20:35:37 +0200] "GET /\ foo=bat\ HTTP/1.0" 400 299 "-" "-" "-"
Ora sto cercando di ottenere supporto per nessuna, una o più occorrenze di \"
, ma non riesco a trovare una soluzione. Utilizzando regexpal.com Ho arrivato fino a questo finora:
^(\d+\.\d+\.\d+\.\d+)\s+[^\s]+\s+[^\s]+\s+\[(\d+)/([A-Za-z]+)/(\d+):(\d+):(\d+):(\d+)\s+\+\d+\]\s+"(.|\\(?="))*"
Ecco solo la parte modificata:
# request uri
'"(.|\\(?="))*"' .
Tuttavia, è troppo avido. Mangia tutto fino all'ultimo "
, quando dovrebbe mangiare solo fino al primo "
non preceduto da un \
. Ho anche provato introducendo il requisito che non c'è \
prima della "
che voglio, ma mangia ancora alla fine della stringa (Nota: ho dovuto aggiungere estranei \
personaggi per fare questo lavoro in PHP):
# request uri
'"(.|\\(?="))*[^\\\\]"' .
* ?
::? Se utilizzato subito dopo una delle quantificatori
, +, o {}, rende il quantificatore non avido (corrispondente al numero minimo di volte)
# request uri
'"(.|\\(?="))*?[^\\\\]"' .
Ma poi mi ha colpito
La regex 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+|-)
aggiornamento 5 maggio 2009:
ho scoperto un piccolo difetto nella espressione regolare a causa di analisi milioni di righe: si rompe sulle linee che contengono il carattere di backslash a destra prima del doppio citazione. In altre parole:
...\\"
interromperà l'espressione regolare. Apache non registra ...\"
ma eviterà sempre la barra retroversa su \\
, quindi è lecito ritenere che quando ci sono due caratteri di barra rovesciata prima della virgoletta doppia.
Qualcuno ha un'idea su come risolvere questo problema con l'espressione regolare?
risorse utili: the JavaScript Regexp documentation at developer.mozilla.org e regexpal.com
Potresti aggiungere ulteriori informazioni sulla tua espressione regolare a beneficio di tutti? Sono riuscito a malapena a capire quello che ho scritto ... grazie :) – mark
(?: A | B) corrisponde a A o B. \\. corrisponde a una barra rovesciata che segue qualsiasi carattere tranne newline. [^ \\ "] corrisponde a qualsiasi carattere tranne il backslash e il doppio preventivo. Mettere tutto insieme fa esattamente quello che vuoi, +1. –
bellissimo ... grazie amico. –