2009-03-29 3 views
10

Первоначально это вопрос, который я хотел задать, но, исследуя детали для вопроса, я нашел решение и подумал, что это может представлять интерес для других.Регулярное выражение, которое совпадает между кавычками, содержащими экранированные кавычки

В 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

ответ

26

Попробуйте это:

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

Это регулярное выражение соответствует двойной кавычки, за которым следует последовательность либо любой символ, кроме \ и " или сбежавшего последовательности \α (где α может быть любым символом) f омраченный последним символом двойной кавычки. (?:expr) синтаксис - это просто группа, не связанная с захватом.

+2

Не могли бы вы добавить дополнительную информацию о своем регулярном выражении на благо всех? Мне едва удалось понять, что я написал ... спасибо :) – mark

+5

(?: A | B) соответствует A или B. \\. соответствует обратной косой черте после любого символа, кроме новой строки. [^ \\ "] соответствует любому символу, кроме обратной косой черты и двойной кавычки. Сочетание всего этого делает именно то, что вы хотите, +1. –

+0

красивый ... спасибо человеку. –