当我跑步时
/(a)/g.exec('a a a ').length
我得到了
2
但我认为它应该返回
3
因为字符串中有3个a
,而不是2!
为什么?
我希望能够在RegEx中搜索字符串的所有出现并迭代它们。
FWIW:我正在使用node.js
答案 0 :(得分:34)
exec()
仅返回第一个匹配的捕获集,而不是您期望的匹配集。所以你真正看到的是$0
(整个匹配,“a”)和$1
(第一次捕获) - 即。长度为2. exec()
的数组同时设计为可以再次调用 来获取 next 匹配的捕获。来自MDN:
如果正则表达式使用“g”标志,则可以多次使用exec方法在同一个字符串中查找连续匹配。执行此操作时,搜索从正则表达式的lastIndex属性指定的str的子字符串开始(test也将提升lastIndex属性)。
答案 1 :(得分:22)
您可以改为使用match
:
'a a a'.match(/(a)/g).length // outputs: 3
答案 2 :(得分:7)
你只匹配第一个a。长度为2的原因是它找到第一个匹配和第一个匹配的括号组部分。在你的情况下,他们是相同的。
考虑这个例子。
var a = /b(a)/g.exec('ba ba ba ');
alert(a);
输出ba, a
。数组长度仍为2,但更明显的是发生了什么。 “ba”是全场比赛。 a
是带括号的第一个分组匹配。
MDN documentation支持这一点 - 只返回第一个匹配和包含的组。要查找所有匹配项,您可以使用mVChr所述的match()。
答案 3 :(得分:4)
的代码:强> 的
alert('a a a'.match(/(a)/g).length);
的输出:强> 的
3
答案 4 :(得分:3)
while循环可以帮助您
x = 'a a a a';
y = new RegExp(/a/g);
while(null != (z=y.exec(x))) {
console.log(z); // output: object
console.log(z[0]); // ouput: "a"
}
如果您添加计数器,那么您将获得它的长度。
x = 'a a a a';
counter = 0;
y = new RegExp(/a/g);
while(null != (z=y.exec(x))) {
console.log(z); // output: object
console.log(z[0]); // output: "a"
counter++;
}
console.log(counter); // output: 4
这是非常安全的,即使它没有找到任何匹配,它只是退出而计数器将为0
主要目的是告诉如何使用RegExp循环并从相同匹配的RegExp的字符串中获取所有值
答案 5 :(得分:1)
regexp.exec(str)
返回第一个匹配项或整个匹配项以及第一次捕获(re = /(a)/g;
时),如其他答案中所述
const str = 'a a a a a a a a a a a a a';
const re = /a/g;
const result = re.exec(str);
console.log(result);
但是它也记住在regexp.lastIndex
属性中的位置。
下一个呼叫从regexp.lastIndex
开始搜索并返回下一个匹配项。
如果没有更多匹配项,则regexp.exec
返回null,并将regexp.lastIndex
设置为0。
const str = 'a a a';
const re = /a/g;
const a = re.exec(str);
console.log('match : ', a, ' found at : ', re.lastIndex);
const b = re.exec(str);
console.log('match : ', b, ' found at : ', re.lastIndex);
const c = re.exec(str);
console.log('match : ', c, ' found at : ', re.lastIndex);
const d = re.exec(str);
console.log('match : ', d, ' found at : ', re.lastIndex);
const e = re.exec(str);
console.log('match : ', e, ' found at : ', re.lastIndex);
这就是为什么您可以使用while循环,当匹配为null
const str = 'a a a';
const re = /a/g;
while(match = re.exec(str)){
console.log(match, ' found at : ', match.index);
}
答案 6 :(得分:0)
就您的示例而言,.match()
是您的最佳选择。但是,如果确实需要子组,则可以创建生成器函数。
function* execAll(str, regex) {
if (!regex.global) {
console.error('RegExp must have the global flag to retrieve multiple results.');
}
let match;
while (match = regex.exec(str)) {
yield match;
}
}
const matches = execAll('a abbbbb no match ab', /\b(a)(b+)?\b/g);
for (const match of matches) {
console.log(JSON.stringify(match));
let otherProps = {};
for (const [key, value] of Object.entries(match)) {
if (isNaN(Number(key))) {
otherProps[key] = value;
}
}
console.log(otherProps);
}
虽然大多数 JS 程序员认为污染原型是不好的做法,但您也可以将其添加到 RegExp.prototype
。
if (RegExp.prototype.hasOwnProperty('execAll')) {
console.error('RegExp prototype already includes a value for execAll. Not overwriting it.');
} else {
RegExp.prototype.execAll =
RegExp.prototype = function* execAll(str) {
if (!this.global) {
console.error('RegExp must have the global flag to retrieve multiple results.');
}
let match;
while (match = this.exec(str)) {
yield match;
}
};
}
const matches = /\b(a)(b+)?\b/g.execAll('a abbbbb no match ab');
console.log(Array.from(matches));