【问题标题】:What's wrong with this regex - something to do with the reluctant quantifier?这个正则表达式有什么问题 - 与不情愿的量词有关?
【发布时间】:2014-01-07 12:51:11
【问题描述】:

有人知道为什么这在 javascript 中不起作用吗? (尝试使用 Chrome 和 Firefox):

console.log('"my name is"'.match(/"?(.*?)"?/));

输出这个:

[""", "", index: 0, input: ""my name is""] 

我预料到了:

[""my name is"", "my name is", index: 0, input: ""my name is""]

我对解决问题的替代方法不感兴趣,而且对于我试图实现的目标(我现在采取的方式略有不同)来说,这并不是一个完整的解决方案 - 我只是对为什么感兴趣匹配失败。

我希望不情愿的量词匹配所有内容,但不包括最终报价。我不明白为什么表达式无法匹配任何内容?

【问题讨论】:

    标签: javascript regex reluctant-quantifiers


    【解决方案1】:

    考虑

    > "foo".match(/.*?/)
    [""]
    

    ? 告诉正则表达式尽可能少地匹配,空字符串是它可以得到的最好的。同样,

    > "foo".match(/x/)
    null
    > "foo".match(/x?/)
    [""]
    

    可选模式永远不会失败,并且匹配其内容或空字符串。

    在您的示例中,它首先匹配引号,然后将空字符串与(.*?) 匹配,将(另一个)空字符串与"? 匹配。由于两个测试都成功了,所以它不会再看下去了,结果只是一个引用。

    【讨论】:

      【解决方案2】:

      问题是模式中的所有内容,包括周围的引号,都是可选的。这意味着它可以很容易地匹配一个空字符串。那么正则表达式引擎内部发生了什么?

      • 引擎尝试匹配第一个"?。没问题,它匹配字符串中的第一个"
      • 引擎移动到模式的下一部分,.*?。嗯,第一个 " 之后的零长度子字符串与此匹配,因此它继续。
      • 引擎移动到模式的最后一部分,"?。下一个字符是m,所以这不匹配,但没关系,因为最后一个" 是可选的,所以它不会被捕获。

      因此第一个匹配就是第一个"

      【讨论】:

      • 我没有注意到我的输出开头有 3 个引号 - 而不是 2 个 - 这应该是我的大线索!
      【解决方案3】:

      你的正则表达式可以匹配任何东西(好吧,只要没有换行)。

      • "? : 没有约束(可以为空,但如果可能的话不要)
      • .*? : 完全没有约束,可以是整个字符串,也可以是空字符串
      • "? :无​​约束(可以为空)

      表达式没有匹配任何内容:第一个匹配项是"

      【讨论】:

        【解决方案4】:

        当您说.*? 时,实际上是在要求 JavaScript 将 0 匹配到无限匹配,但随后您立即使用 ? 控制它,这意味着非贪婪搜索。只需删除其中的?,就可以了。

        var regEx = /"?.*"?/;
        console.log('"my name is"'.match(regEx)[0]);
        console.log('my name is'.match(regEx)[0]);
        

        这个正则表达式将匹配两个字符串,有或没有"

        【讨论】:

        • "我只是对匹配失败的原因感兴趣"
        【解决方案5】:

        你可以使用这个代码:

        console.log('"my name is"'.match(/"?(.*)\"?/));
        

        结果:

        [""my name is"", "my name is"", index: 0, input: ""my name is""] 
        

        您的问题的解释

        REGEX:     /"?(.*)?"?/g
        

        您的代码中存在(.*)? 的问题。它是repeated capturing group 的一种类型。

        重复捕获组将仅捕获最后一次迭代。放一个 围绕重复组捕获组以捕获所有迭代或 如果您对数据不感兴趣,请改用非捕获组

        由于您的输入是 "my name is" ,使用 (.)* 它将捕获 "my name is"

        但在(.*)?的情况下,由于是重复捕获,所以只会捕获最后一次迭代,即"

        请参阅 Repeating a Capturing Group 了解更多详情。

        【讨论】:

        • 引用 OP:我对解决问题的替代方法不感兴趣 [...] 我只是对匹配失败的原因感兴趣。
        • 我更新了我的答案。我希望你会明白原因的。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多