当你重复一个捕获组时,在大多数情况下,只保留最后一个捕获;覆盖任何先前的捕获。在某些方面,例如.NET,你可以得到所有的中间捕获,但这不是JavaScript的情况。 也就是说,在JavaScript中,如果你有一个包含 N 个捕获组的模式,那么你只能在每个匹配中捕获 N 个字符串,即使其中一些组是重复的。 所以一般来说,这取决于你需要做什么:
var text = "a;b;<c;d;e;f>;g;h;i;<no no no>;j;k;<xx;yy;zz>";
var r = /<(\w+(;\w+)*)>/g;
var match;
while ((match = r.exec(text)) != null) {
print(match[1].split(";"));
}
// c,d,e,f
// xx,yy,zz
// EX.1
"foo bar baz".match(/^(\w+) (\w+) (\w+)$/)
...这就产生了...
// RES.1
['foo bar baz', 'foo', 'bar', 'baz']
**为什么?**因为你声明性地捕获了3个不同的 * 组 *。比较一下:
// EX.2 (Note the /g lobal flag and absence of the `^` and `$`)
"foo bar baz".match(/(\w+)/g)
...这就产生了...
// RES.2
['foo', ' bar', ' baz']
这是因为.match方法具有双重功能。在一个非/g捕获匹配中,它将返回match作为返回数组中的第一个元素,并返回each capture group作为同一数组中的一个附加节点。这是因为match()只是RegExp.prototype.exec的语法糖实现。 因此,Res.2中结果的格式是/g匹配标志的结果,它向编译器表明,“每次找到此模式的匹配时,返回它,并从该匹配的末尾继续,看看是否还有更多”。由于RegExp.prototype.exec返回第一次出现,但您提供了“/goahead and continue until we run out”标志,因此您会看到一个集合多次包含第一次出现的内容。
2. String.prototype.matchAll
如果你确实需要完整的“exec match”语法,并希望捕获所有 n 个匹配,并且你愿意使用/g匹配标志(你必须这样做),你需要matchAll。它返回一个RegExpStringIterator,这是一种特殊类型的集合,需要使用/g类型。让我们在EX.2中使用matchAll重新运行相同的查询:
// EX.3a
"foo bar baz".matchAll(/(\w+)/g)
// RES.3a
RegExpStringIterator
// EX.6a
console.log("foo bar baz".replace(/(...) (...) (...)/, "The first word is '$1'.\nThe second word is '$2'.\nThe third word is '$3'."))
// RES.6a
"The first word is 'foo'.
The second word is 'bar'.
The third word is 'baz'."
6条答案
按热度按时间v6ylcynt1#
当你重复一个捕获组时,在大多数情况下,只保留最后一个捕获;覆盖任何先前的捕获。在某些方面,例如.NET,你可以得到所有的中间捕获,但这不是JavaScript的情况。
也就是说,在JavaScript中,如果你有一个包含 N 个捕获组的模式,那么你只能在每个匹配中捕获 N 个字符串,即使其中一些组是重复的。
所以一般来说,这取决于你需要做什么:
/(pattern)+/
,而可能匹配/pattern/g
,可能在exec
循环中参考资料
示例
下面是一个在文本中匹配
<some;words;here>
的例子,使用exec
循环,然后在;
上拆分以获得单个单词(see also on ideone.com):使用的模式是:
这与
<word>
、<word;another>
、<word;another;please>
等匹配。组2重复捕获任意数量的单词,但它只能保留最后一次捕获。整个单词列表由组1捕获;这个字符串在split
上是split
。相关问题
sqougxex2#
不如这样吧
"foo bar baz".match(/(\w+)+/g)
ldioqlga3#
除非你对如何拆分字符串有更复杂的要求,否则你可以拆分它们,然后返回初始字符串:
nbewdwxp4#
试着用“g”:
4xy9mtcn5#
您可以使用LAZY评估。所以,不要用 (GREEDY),试试用?(懒惰)
正则表达式:(\s\w+)?
结果:
匹配1:foo
匹配2:酒吧
匹配3:巴兹
mzillmmw6#
我已经通读了这个问题和所有的答案,我觉得他们留下了很多模棱两可的地方。所以,为了澄清事实:
1. String.prototype.match
我希望看到下面这行JavaScript:
"foo bar baz".match(/^(\s*\w+)+$/)
返回如下内容:["foo bar baz", "foo", " bar", " baz"]
为了获得所需的输出,需要显式地捕获所有三个组(特别是因为您使用
^...$
将模式括起来,表明您希望整个字符串在一个匹配中通过测试)。String.prototype.match
将返回该格式([FULL_MATCH, CAP1, CAP2, CAP3, ... CAPn]
)-它是“exec”响应(之所以这么叫是因为String.prototype.match是RegExp.prototype.exec的一个实现)-当表达式匹配目标字符串 * 而没有设置/g
匹配标志 * 时。考虑:...这就产生了...
**为什么?**因为你声明性地捕获了3个不同的 * 组 *。比较一下:
...这就产生了...
这是因为
.match
方法具有双重功能。在一个非/g
捕获匹配中,它将返回match作为返回数组中的第一个元素,并返回each capture group作为同一数组中的一个附加节点。这是因为match()
只是RegExp.prototype.exec
的语法糖实现。因此,Res.2中结果的格式是
/g
匹配标志的结果,它向编译器表明,“每次找到此模式的匹配时,返回它,并从该匹配的末尾继续,看看是否还有更多”。由于RegExp.prototype.exec返回第一次出现,但您提供了“/g
oahead and continue until we run out”标志,因此您会看到一个集合多次包含第一次出现的内容。2. String.prototype.matchAll
如果你确实需要完整的“exec match”语法,并希望捕获所有 n 个匹配,并且你愿意使用
/g
匹配标志(你必须这样做),你需要matchAll
。它返回一个RegExpStringIterator
,这是一种特殊类型的集合,需要使用/g
类型。让我们在EX.2中使用matchAll
重新运行相同的查询:因为它返回了一个迭代器,为了真正获得数据,我们将使用一个扩展运算符(
...<ITERATOR>
)。因为我们需要一些东西来将它扩展到其中,所以我们将整个数组封装在Array构造函数简写([...<ITERATOR>]
)中。正如您所看到的,有3个匹配,每个都是
[<MATCH>, <CAPGROUP>]
数组。实际上,这一切都归结为
match
返回的是匹配,而不是捕获。如果一个匹配碰巧是一个捕获(或包含多个),当你把它们放在括号里时,把它们分开是很有帮助的。实际上,"foo bar baz".match(/\w+/g)
(注意/g
的存在和捕获括号的缺失)仍然会产生['foo', 'bar', 'baz']
。它找到了3个匹配项,您没有指定想要的组,因此它执行了查找它们的方式。我相信,所有这些在很大程度上都是由于对RegExp如何返回结果的巨大误解。即
3. GROUP不是MATCH
这里的部分歧义是术语。同一个match中可以 * 包含多个捕获组。一个组中不能有多个匹配项。想想维恩图:
这可能更容易使用语法可视化。假设我们使用正则表达式:
与Ex.1相比,我唯一的变化是为每个捕获组(由括号中包含的模式定义的匹配部分-
(...)
)分配了一个名称(?<NAME>
语法)。因为它们是命名的,所以out响应数组有一个额外的属性:.groups:因为我们显式地命名了所有三个捕获组,所以我们可以看到我们有一个MATCH(包含完整匹配和所有3个捕获组内容的数组),沿着我们的命名捕获对象。
所以,最后,让我们用额外的信息来尝试你的第一次尝试:
等等,怎么回事?
因为您只声明性地指定了一个捕获组(我将其标记为“GROUPn”),所以您只提供了一个“槽”供捕获进入。
简而言之:这并不是说你的表情没有捕捉到所有三个元素。那就是“slot”--当返回值在响应中到达时用来存储返回值的变量 * 被覆盖了两次 。所有这些都是在说: 不能在一个捕获组中存储多个捕获 *(至少在ECMA的RegExp引擎中是这样)。
你当然可以存储多个 * 匹配 *(如果这就是你所需要的,嘿,太好了),但是有时候你不能在应用结果集之前对其进行验证。
最后举一个例子:
在这个例子中,我们需要在replacement match中的所有三个捕获,所以我们可以在同一个替换操作中直接引用每个捕获。如果我们用你的表情来试一下:
......我们最终会得到令人困惑的不准确的......
希望这对将来的人有所帮助。