意外的非贪婪JS正则表达式结果

时间:2013-08-21 12:19:38

标签: javascript regex

为什么

/<.+?> e/.exec("a <b> c <d> e")

(意外地)返回

["<b> c <d> e"]

而不是

["<d> e"]

非贪婪的运营商似乎什么都不做......

5 个答案:

答案 0 :(得分:3)

"<b> c <d> e"是完全有效的结果。你的正则表达式&#34;匹配<然后匹配> e&#34; - 这正是你得到的。 &#34;直观&#34; "<d> e"可能看起来更匹配,但是,正则表达式引擎没有直觉,它只是找到匹配并停在那里的第一个子字符串。

当你在两场或多场比赛之间做出选择时,贪婪会发挥作用 - 这不是这里的情况,因为只有一场比赛。如果您的字符串有两个> e,则会有所不同:

/<.+> e/.exec("a <b> c <d> e more > e")
> ["<b> c <d> e more > e"]
/<.+?> e/.exec("a <b> c <d> e more > e")
> ["<b> c <d> e"]

答案 1 :(得分:3)

?使其变得非贪婪,您正在经历的行为正在发生,因为您并没有告诉它在>处结束尝试匹配> e不属于{{{ 1}}。目前;

/<.+?> e/
  1. 直到<
  2. 为止
  3. 匹配到>或行尾
    1. 如果是行尾,请返回null
    2. 如果是>
      1. 如果是> e,则完全匹配
      2. 否则,请加入并恢复2
  4. 请记住,.+会很乐意匹配>,空格和字母,因此这些内容会被包含在内。看起来像你想要的

    /<[^>]+?> e/
    
    1. 直到<
    2. 为止
    3. 匹配所有非>
    4. >或找到了行尾
      1. 如果是行尾,请返回null
      2. 如果是>
        1. 如果是> e,则完全匹配
        2. 否则,请返回步骤1
    5. 导致

      /<[^>]+?> e/.exec("a <b> c <d> e")
      // ["<d> e"]
      

      这种情况发生的原因是当遇到不属于>的{​​{1}}时,它知道它的起始位置一定是错误的,所以继续沿着文本继续直到下一个> e

答案 2 :(得分:3)

这可以让你理解懒惰运算符的作用:

/<.+?> e/.exec("a <b> c <d> e <f> e")` // -> ["<b> c <d> e", "<f> e"]
/<.+> e/.exec("a <b> c <d> e <f> e")`  // -> ["<b> c <d> e <f> e"]

<.+?> e表示:找到<后,找到第一个 > e

<.+> e表示:找到<后,找到最后 > e

在您的具体情况下,您可以简单地使用<[^>]+> e(这更快,因为它更快 - 当它可能时,总是更喜欢X[^X]X符号而不是X.*?X符号。 / p>

答案 3 :(得分:2)

来自regular-expressions.info

  

这是一个非常重要的要点:一个正则表达式的引擎   将始终返回最左边的匹配,即使“更好”的匹配可以   可以在以后找到。

正则表达式引擎从左侧穿过字符串,对于每个字符,说“我能从这里找到匹配吗?”非贪婪的运算符永远不会阻止在没有匹配的情况下找到匹配,因此引擎将继续尝试,这意味着当它从第一个<开始检查时,它将找到匹配并返回它立刻(没有检查从第二个<开始的匹配,因为它没有那么远)。

为了匹配你想要的东西,一组尖括号后跟一个“e”,你只需要确保中间没有>

<[^>]+>[ ]e

(请注意,为了清晰起见,空格位于字符类中,而不是因为它需要。)

答案 4 :(得分:2)

通过使.+延迟,模式必须在> e第一次之后找到匹配的<.+?。既然如此,在你的情况下是子串<b> c,模式的其余部分> e尚未匹配,所以表达式的.+部分一直在继续,直到最后> e部分最后匹配......

'a <b> c <d> e'
 xx//<-- no matches
   <//<-- opening < matches, switch to .+?
    b//<-- matched by .+
     > c//<-- does not match > e, but does match .+
         <d// matched by .+
           > e// matches rest of expression (> e), the resulting match is:

   <b> c <d> e

在您的情况下,我不是使用惰性运算符,而是选择:

/(?:<)[^>]+> e/
//or even
/<[^>]+>\s+e/