Первоначально это вопрос, который я хотел задать, но, исследуя детали для вопроса, я нашел решение и подумал, что это может представлять интерес для других.Регулярное выражение, которое совпадает между кавычками, содержащими экранированные кавычки
В 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+|-)
Update 5 мая 2009:
я обнаружил небольшой недостаток в регулярном выражении из-за разбора миллионы строк: он разбивает на линиях, которые содержат символ обратной косой черты перед двойной цитаты. Другими словами:
...\\"
будет разорвать регулярное выражение. Apache не будет регистрировать ...\"
, но всегда будет избегать обратной косой черты до \\
, поэтому можно с уверенностью предположить, что при наличии двух символов обратной косой черты перед двойной цитатой.
У кого-нибудь есть идея, как исправить это с помощью регулярного выражения?
Полезные ресурсы: the JavaScript Regexp documentation at developer.mozilla.org и regexpal.com
Не могли бы вы добавить дополнительную информацию о своем регулярном выражении на благо всех? Мне едва удалось понять, что я написал ... спасибо :) – mark
(?: A | B) соответствует A или B. \\. соответствует обратной косой черте после любого символа, кроме новой строки. [^ \\ "] соответствует любому символу, кроме обратной косой черты и двойной кавычки. Сочетание всего этого делает именно то, что вы хотите, +1. –
красивый ... спасибо человеку. –