【问题标题】:Regular expression that matches between quotes, containing escaped quotes引号之间匹配的正则表达式,包含转义引号
【发布时间】:2010-10-16 05:06:02
【问题描述】:

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

在 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 源代码中提供带有 cmets 和更好格式的解决方案:

$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+|-)

2009 年 5 月 5 日更新:

由于解析了数百万行,我在正则表达式中发现了一个小缺陷:它在双引号之前包含反斜杠字符的行上中断。换句话说:

...\\"

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

有人知道如何用正则表达式解决这个问题吗?

有用的资源:@​​987654321@ 和 regexpal.com

【问题讨论】:

    标签: regex pcre


    【解决方案1】:

    试试这个:

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

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

    【讨论】:

    • 您能否添加一些有关您的正则表达式的更多信息,以造福所有人?我几乎无法理解我写的内容......谢谢:)
    • (?:A|B) 匹配 A 或 B。\\.匹配除换行符以外的任何字符后的反斜杠。 [^\\"] 匹配除反斜杠和双引号之外的任何字符。将它们放在一起完全符合您的要求,+1。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多