包含转义引号的引号之间匹配的正则表达式

mar*_*ark 10 regex pcre

这本来是一个我想问的问题,但在研究问题的细节时,我找到了解决方案,并认为其他人可能会感兴趣.

在Apache中,完整请求是双引号,并且内部的任何引号始终使用反斜杠进行转义:

1.2.3.4 - - [15/Apr/2005:20:35:37 +0200] "GET /\" foo=bat\" HTTP/1.0" 400 299 "-" "-" "-"
Run Code Online (Sandbox Code Playgroud)

我正在尝试构建一个匹配所有不同字段的正则表达式.我当前的解决方案总是停在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+|-)
Run Code Online (Sandbox Code Playgroud)

我想我也会从我的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
    ';';
Run Code Online (Sandbox Code Playgroud)

使用这个与URL不包含其他引号的简单情况工作正常:

1.2.3.4 - - [15/Apr/2005:20:35:37 +0200] "GET /\ foo=bat\ HTTP/1.0" 400 299 "-" "-" "-"
Run Code Online (Sandbox Code Playgroud)

现在我正试图获得支持,一次或多次出现\",但无法找到解决方案.使用regexpal.com到目前为止我已经想出了这个:

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

这里只有改变的部分:

    # request uri
    '"(.|\\(?="))*"' .
Run Code Online (Sandbox Code Playgroud)

但是,它太贪心了.它会吃掉所有东西直到最后",它应该只吃到第一个"没有先于a \.我也尝试\过在"我想要之前没有引入的要求,但它仍然吃到字符串的末尾(注意:我必须添加无关的\字符才能在PHP中使用):

    # request uri
    '"(.|\\(?="))*[^\\\\]"' .
Run Code Online (Sandbox Code Playgroud)

但是它击中了我:*?:如果在任何量词之后立即使用,+,?或{},使量词非贪婪(匹配最小次数)

    # request uri
    '"(.|\\(?="))*?[^\\\\]"' .
Run Code Online (Sandbox Code Playgroud)

完整的正则表达式:

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

2009年5月5日更新:

我在regexp中发现了一个小缺陷,因为解析了数百万行:它在包含双引号之前的反斜杠字符的行上中断.换一种说法:

...\\"
Run Code Online (Sandbox Code Playgroud)

将破坏正则表达式.Apache不会记录...\"但总会将反斜杠转义为\\,因此可以安全地假设在双引号之前有两个反斜杠字符.

任何人都知道如何使用正则表达式解决这个问题?

有用的资源:developer.mozilla.orgregexpal.com上的JavaScript Regexp文档

Gum*_*mbo 26

试试这个:

"(?:[^\\"]+|\\.)*"
Run Code Online (Sandbox Code Playgroud)

此正则表达式匹配双引号字符,后跟除了\和/ "或转义序列\?(其中?可以是任何字符)之后的任何字符的序列,后跟最后的双引号字符.该语法只是一个非捕获组.(?:expr)

  • (?:A | B)匹配A或B. \\.匹配除换行符之外的任何字符后面的反斜杠.[^ \\"]匹配除反斜杠和双引号之外的任何字符.将它们放在一起完全符合您的要求,+ 1. (5认同)
  • 为了所有人的利益,您能否为您的正则表达式添加更多信息?我几乎无法理解我写的内容......谢谢:) (2认同)