2009-03-29 9 views
10

C'était à l'origine une question que je voulais poser, mais tout en recherchant les détails de la question, j'ai trouvé la solution et j'ai pensé qu'elle pourrait intéresser les autres.Expression régulière qui correspond entre guillemets, contenant des citations échappées

Dans Apache, la demande complète est entre guillemets doubles et les guillemets sont toujours à l'intérieur se sont échappés avec une barre oblique inverse:

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

Je suis en train de construire une expression régulière qui correspond à tous les champs distincts. Ma solution actuelle s'arrête toujours sur la première citation après la GET/POST (en fait je ne ai besoin de toutes les valeurs, y compris la taille transférée):

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

Je suppose que je vais aussi fournir ma solution de ma source PHP avec des commentaires et une meilleure mise en forme:

$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 
    ';'; 

l'utilisation de ce avec un simple cas où l'URL ne contient pas d'autres citations fonctionne très bien:

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

Maintenant j'essaye d'obtenir le support pour aucun, une ou plusieurs occurrences de \" dedans, mais ne peux pas trouver une solution. En utilisant regexpal.com Je suis venu avec ce à ce jour:

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

est ici que la partie a changé:

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

Cependant, il est trop gourmand. Il mange tout jusqu'à la dernière ", quand il devrait seulement manger jusqu'à la première " non précédé d'un \. J'ai aussi essayé d'introduire l'obligation qu'il n'y a pas \ avant la " que je veux, mais il mange encore à la fin de la chaîne (Note: je devais ajouter \ étrangers caractères pour faire ce travail en PHP):

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

Mais il m'a frappé: * ?: Si elle est utilisée immédiatement après l'une des quantificateurs , +, ou {}, rend le quantificateur non gourmand (correspondant au nombre minimum de fois)

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

La pleine regex:

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

Mise à jour 5 mai 2009:

je découvre un petit défaut dans l'expression rationnelle due analyse syntaxique des millions de lignes: il se brise sur les lignes qui contiennent le caractère anti-slash juste avant la double citation. En d'autres termes:

...\\" 

rompra la regex. Apache ne consignera pas ...\" mais échappera toujours à la barre oblique inverse à \\. Il est donc prudent de supposer que lorsqu'il y a deux caractères antislash avant le double guillemet.

Quelqu'un a une idée de comment résoudre ce problème avec l'expression régulière?

Ressources utiles: the JavaScript Regexp documentation at developer.mozilla.org et regexpal.com

Répondre

26

Essayez ceci:

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

Cette expression régulière correspond à un double caractère de citation suivie d'une séquence soit un caractère autre que \ et " ou une séquence échappé \α (où α peut être n'importe quel caractère) f suivi par le dernier caractère de guillemets doubles. Le (?:expr) La syntaxe est juste un groupe non-capturant.

+2

Pourriez-vous ajouter plus d'informations sur votre regex pour le bénéfice de tous? J'ai à peine réussi à comprendre ce que j'ai écrit ... merci :) – mark

+5

(?: A | B) correspond à A ou B. \\. correspond à une barre oblique inverse qui suit n'importe quel caractère, sauf le saut de ligne. [^ \\ "] correspond à n'importe quel caractère à l'exception des barres obliques inverses et des guillemets doubles.Mettre tout ensemble fait exactement ce que vous voulez, +1 .. –

+0

belle ... merci l'homme. –

Questions connexes