为什么String.match()在出现全局标志时不会产生预期的结果?

时间:2013-07-28 20:56:55

标签: javascript regex

我正在尝试这场比赛

'/links/51f5382e7b7993e335000015'.match(/^\/links\/([0-9a-f]{24})$/g)

得到了:

['/links/51f5382e7b7993e335000015']

虽然我在期待:

['/links/51f5382e7b7993e335000015', '51f5382e7b7993e335000015']

在我移除全球旗帜之前我没有运气,我认为这不会影响我的结果!

删除全局标志后

'/links/51f5382e7b7993e335000015'.match(/^\/links\/([0-9a-f]{24})$/)

制备:

[ '/links/51f5382e7b7993e335000015',
  '51f5382e7b7993e335000015',
  index: 0,
  input: '/links/51f5382e7b7993e335000015' ]

这很酷,但阅读我无法弄清楚的文档:

  • 为什么第一张表格不起作用
  • 为什么全局标志会干扰()匹配
  • 如何在没有indexinput属性
  • 的情况下获得我的预期结果

JavaScript Regex and Submatches上,最佳答案是:

  

如果设置了全局修改器,使用String的match()函数将不会返回捕获的组。

然而,

> 'fofoofooofoooo'.match(/f(o+)/g) 
["fo", "foo", "fooo", "foooo"]

似乎可以很好地生成捕获的组。

谢谢。

2 个答案:

答案 0 :(得分:3)

来自this msdn documentation的匹配方式:

  

如果未设置全局标志(g),数组的元素零包含整个匹配,而元素1到n包含任何子匹配。此行为与行为相同未设置全局标志时的exec方法(正则表达式)(JavaScript)。如果设置了全局标志,则元素0到n包含发生的所有匹配。

强调我的。

所以,在第一个案例

'/links/51f5382e7b7993e335000015'.match(/^\/links\/([0-9a-f]{24})$/g)

由于设置了/g修饰符,它将仅返回发生的完整匹配,而不返回子匹配。这就是为什么你只有一个单元素的数组。由于该正则表达式只有一个匹配。

第二个案例

'/links/51f5382e7b7993e335000015'.match(/^\/links\/([0-9a-f]{24})$/)
未设置

/g修饰符。因此数组包含0th索引处的完全匹配。数组中的其他元素(第一个索引)是子匹配 - 在本例中是第一个捕获组。


至于最后一个例子

'fofoofooofoooo'.match(/f(o+)/g)

同样,由于设置了/g修饰符,它将返回字符串中的所有匹配项,而不是子匹配项。因此,在字符串中,正则表达式f(o+)匹配4次:

fo    - 1st complete match (sub-match 'o' in 1st captured group ignored)
foo   - 2nd complete match (sub-match 'oo' ignored)
fooo  - 3rd complete match (sub-match 'ooo' ignored)
foooo - 4th complete match (sub-match 'oooo' ignored)

如果您使用不带/g修饰符的最后一个正则表达式,则会将每个子匹配作为第一个匹配的单独元素。尝试:

'fofoofooofoooo'.match(/f(o+)/)

你会得到:

["fo", "o"]  // With index and input element of course.

如果没有/g,它会在首次匹配(fo)后停止,并返回整个匹配和子匹配。

答案 1 :(得分:1)

根据MDN,如果未指定g标志,则返回与RegExp.exec()相同的结果,这将返回包含捕获括号的项目的数组。

如果指定了g标志,则返回包含所有匹配项的数组。

此描述与问题中的示例一致,但您的两个示例是带有橙子的苹果:

  • 您的“链接”正则表达式匹配整个输入字符串一次,可能与一个捕获的组匹配,具体取决于标记。
  • 您的/f(o+)/g正则表达式匹配输入中的多个子字符串。