这本来是我想问的一个问题,但在研究问题的细节时,我找到了解决方案,并认为其他人可能会对它感兴趣。
在 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
'"(.|\\(?="))*"' .
不过,也太贪心了。它吃完所有东西,直到最后一个"
,它应该只吃到第一个,"
前面没有 a \
。\
我还尝试引入在我想要的之前没有的要求"
,但它仍然吃到字符串的末尾(注意:我必须添加无关\
的字符才能在 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+|-)
2009 年 5 月 5 日更新:
由于解析了数百万行,我在正则表达式中发现了一个小缺陷:它在双引号之前包含反斜杠字符的行上中断。换句话说:
...\\"
将打破正则表达式。Apache 不会记录...\"
但总是将反斜杠转义为\\
,因此可以安全地假设当双引号前有两个反斜杠字符时。
任何人都知道如何用正则表达式解决这个问题?
有用的资源: developer.mozilla.org和regexpal.com上的 JavaScript Regexp 文档