代码之家  ›  专栏  ›  技术社区  ›  Graeme Perrow

如何将引号分隔的字符串与regex匹配?

  •  27
  • Graeme Perrow  · 技术社区  · 17 年前

    如果我尝试将引号分隔的字符串与regex匹配,那么以下哪一个是“更好”(其中“更好”意味着效率更高,也不太可能做意外的事情):

    /"[^"]+"/ # match quote, then everything that's not a quote, then a quote
    

    /".+?"/   # match quote, then *anything* (non-greedy), then a quote
    

    对于这个问题,假设空字符串(即“”)不是问题。在我看来(没有Regex新手,但肯定没有专家),这些将是等效的。

    更新 :经过思考,我想改变 + 字符到 * 将正确处理空字符串。

    9 回复  |  直到 9 年前
        1
  •  34
  •   Etienne Neveu    9 年前

    你应该用一号,因为二号是不好的做法。考虑开发人员谁来后,你想匹配字符串后面跟着一个感叹号。他应该使用:

    "[^"]*"!
    

    或:

    ".*?"!
    

    当你的主题是:

    "one" "two"!
    

    第一个regex匹配:

    "two"!
    

    当第二个regex匹配时:

    “一”“二”!
    

    尽可能具体。尽可能使用否定字符类。

    另一个区别是[^“]*可以跨行,而*除非使用单行模式,否则不会跨行。[^“\n]*也排除换行符。

    至于回溯,它匹配的每个字符串中的每个字符的第二个regex回溯。如果缺少右引号,两个正则表达式都将回溯整个文件。只有回溯的顺序不同。因此,理论上,第一个正则表达式更快。在实践中,你不会注意到区别。

        2
  •  11
  •   nico    13 年前

    更复杂,但它处理转义引号和转义反斜杠(转义反斜杠后面跟着引号不是问题)

    /(["'])((\\{2})*|(.*?[^\\](\\{2})*))\1/
    

    实例:
    “你好”世界 比赛 “你好”世界
    “你好”“世界” 比赛 “你好”

        3
  •  9
  •   Harold Bamford    17 年前

    我建议:

    ([\"'])(?:\\\1|.)*?\1
    

    但这仅仅是因为它处理转义的引号字符,并允许“和”都是引号字符。我还建议您仔细阅读这篇深入探讨这个问题的文章:

    http://blog.stevenlevithan.com/archives/match-quoted-string

    但是,除非您有严重的性能问题或无法确定嵌入的引号,否则请使用更简单易读的:

    /".*?"/
    

    我必须承认,非贪婪模式不是基本的Unix风格的“ed”正则表达式,但它们变得相当普遍。我仍然不习惯将运算符分组为(?东西)

        4
  •  5
  •   Leon Timmermans    17 年前

    我想说第二个更好,因为它在终止时失败得更快 " 丢失。第一个将在字符串上回溯,这可能是一个昂贵的操作。如果您使用的是Perl5.10,那么另一个regexp将是 /"[^"]++"/ . 它的含义与版本1相同,但与版本2一样快。

        5
  •  3
  •   PEZ    17 年前

    我会选第二名,因为它更容易阅读。但我仍然希望匹配空字符串,因此我将使用:

    /".*?"/
    
        6
  •  1
  •   Tomalak    17 年前

    从性能的角度(非常重,长串的长循环)我可以想象

    "[^"]*"
    

    比快

    ".*?"
    

    因为后者会对每一步做额外的检查:查看下一个字符。前者可以在不经意间将绳子翻转过来。

    正如我所说,在现实世界中,这几乎不明显。因此,我会选择第二个(如果我当前的regex风格支持它,也就是说),因为它更可读。当然,如果不是第一名的话。

        7
  •  1
  •   Trochee    17 年前

    当输入中的其他地方存在边界字符(示例中为doublequeotes)时,使用negated character类可防止匹配。

    您的示例1:

    /"[^"]+"/ # match quote, then everything that's not a quote, then a quote

    只匹配最小的一对匹配的引号——非常好,大多数时候这就是您所需要的。但是,如果您有嵌套引号,并且您对最大的匹配引号对(或所有匹配引号)感兴趣,那么您的情况就复杂得多。

    幸运的是,达米安·康威已经做好了救援准备: Text::Balanced 如果您发现有多个匹配的引号,是否有。它还具有匹配其他成对标点的优点,例如括号。

        8
  •  0
  •   Douglas Leeder    17 年前

    我比较喜欢第一种雷吉酒,但这当然是一种口味问题。

    第一个可能更有效?

    Search for double-quote
    add double-quote to group
    for each char:
        if double-quote:
            break
        add to group
    add double-quote to group
    

    和一些更复杂的事情有关吗?

        9
  •  0
  •   Paul Tomblin    17 年前

    考虑到我甚至不知道“*?”直到今天,我用正则表达式已经20多年了,我还是会投赞成票。它当然清楚地说明了您要做什么——您要尝试匹配一个不包含引号的字符串。