Первоначально я хотел задать этот вопрос, но, изучая детали вопроса, я нашел решение и подумал, что он может быть интересен другим.
В Apache полный запрос заключен в двойные кавычки, а любые кавычки внутри всегда экранируются обратной косой чертой:
1.2.3.4 - - [15/Apr/2005:20:35:37 +0200] "GET /\" foo=bat\" HTTP/1.0" 400 299 "-" "-" "-"
Я пытаюсь создать регулярное выражение, которое соответствует всем различным полям. Мое текущее решение всегда останавливается на первой кавычке после GET
/ POST
(на самом деле мне нужны только все значения, включая переданный размер):
^(\d+\.\d+\.\d+\.\d+)\s+[^\s]+\s+[^\s]+\s+\[(\d+)/([A-Za-z]+)/(\d+):(\d+):(\d+):(\d+)\s+\+\d+\]\s+"[^"]+"\s+(\d+)\s+(\d+|-)
Полагаю, я также предоставлю свое решение из моего источника PHP с комментариями и улучшенным форматированием:
$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
';';
Использование этого в простом случае, когда URL не содержит других кавычек, работает нормально:
1.2.3.4 - - [15/Apr/2005:20:35:37 +0200] "GET /\ foo=bat\ HTTP/1.0" 400 299 "-" "-" "-"
Теперь я пытаюсь получить поддержку ни одного, одного или нескольких вхождений \"
, но не могу найти решение. Используя regexpal.com, я до сих пор придумал это:
^(\d+\.\d+\.\d+\.\d+)\s+[^\s]+\s+[^\s]+\s+\[(\d+)/([A-Za-z]+)/(\d+):(\d+):(\d+):(\d+)\s+\+\d+\]\s+"(.|\\(?="))*"
Вот только измененная часть:
# request uri
'"(.|\\(?="))*"' .
Однако, это слишком жадный. Он ест все до последнего "
, когда он должен есть только до первого "
, которому не предшествует \
. Я также попытался ввести требование о том, что \
не нужно до "
, которое я хочу, но оно все же съедает до конца строки (Примечание: мне пришлось добавить посторонние символы \
, чтобы это работало в PHP):
# request uri
'"(.|\\(?="))*[^\\\\]"' .
Но затем меня поразило: *?
: При использовании сразу после любого из квантификаторов , +,? Или {} делает квантификатор нежадным (соответствует минимуму количество раз)
# request uri
'"(.|\\(?="))*?[^\\\\]"' .
Полное регулярное выражение:
^(\d+\.\d+\.\d+\.\d+)\s+[^\s]+\s+[^\s]+\s+\[(\d+)/([A-Za-z]+)/(\d+):(\d+):(\d+):(\d+)\s+\+\d+\]\s+"(.|\\(?="))*?[^\\]"\s+(\d+)\s+(\d+|-)
Обновление от 5 мая 2009 г .:
Я обнаружил небольшой недостаток в регулярном выражении из-за разбора миллионов строк: он разбивается на строки, содержащие символ обратной косой черты прямо перед двойной кавычкой. Другими словами:
...\\"
сломает регулярное выражение. Apache не регистрирует ...\"
, но всегда переводит обратную косую черту в \\
, поэтому можно с уверенностью предположить, что, если перед двойной кавычкой есть два символа обратной косой черты.
У кого-нибудь есть идеи, как это исправить с помощью регулярного выражения?
Полезные ресурсы: документация JavaScript Regexp на developer.mozilla.org и regexpal.com