JavaScript正则表达式全局匹配分组

62

更新: 这个问题与这个几乎重复。

我相信我的问题的答案已经存在,但我无法简洁地表达出来。我正在尝试使用JavaScript正则表达式实现以下内容:

var input = "'Warehouse','Local Release','Local Release DA'";
var regex = /'(.*?)'/g;

console.log(input.match(regex));

// Actual:
// ["'Warehouse'", "'Local Release'", "'Local Release DA'"]

// What I'm looking for (without the '):
// ["Warehouse", "Local Release", "Local Release DA"]

有没有使用JavaScript正则表达式的干净方法?显然,我可以自己去掉',但我正在寻找正确的方式来使用正则表达式捕获全局匹配组。


是的,这肯定是一个重复问题,我不确定如何搜索我的问题 :/ - Jondlm
我通过搜索 [javascript] [regex] 全局捕获组 找到了它。 - Barmar
8个回答

115

如果要使用正则表达式完成这个任务,你需要使用.exec()方法来迭代它,以便获得多个匹配组。带有g标志的匹配只会返回多个完整的匹配,而不是像你想要的那样返回多个子匹配。以下是使用.exec()的一种方法。

var input = "'Warehouse','Local Release','Local Release DA'";
var regex = /'(.*?)'/g;

var matches, output = [];
while (matches = regex.exec(input)) {
    output.push(matches[1]);
}
// result is in output here

工作演示:http://jsfiddle.net/jfriend00/VSczR/


如果对字符串内容做出一些假设,你也可以直接使用这个:

var input = "'Warehouse','Local Release','Local Release DA'";
var output = input.replace(/^'|'$/, "").split("','");

工作演示:http://jsfiddle.net/jfriend00/MFNm3/


注意:自2021年以来,随着现代JavaScript引擎的发展,您可以使用str.matchAll(regex)一次性获取所有匹配。


添加了一种非正则表达式的方法来实现这个。 - jfriend00
我使用这个正则表达式 /<img[^>]+?src=(?:(?:'([^']*)')|(?:"([^"]*)")|([^\s]*))/i 应用了一个循环,然后控制台没有响应,Chrome 占用了 1 个完整的 CPU 核心。 - jscripter
哦,我忘记加上g修饰符了。现在没问题了。 - jscripter
1
这段代码在jslink中会失败...请改用以下方式:while ((matches = regex.exec(input)) !== null){ - keithics
@keithics - 世界上jslink返回的是什么,既不是null,又是falsey,会导致原始代码无法工作?这很奇怪。.exec()应该返回一个数组或null,所以原始代码应该可以很好地检测到没有匹配。 - jfriend00
显示剩余5条评论

10

String.prototype.matchAll现在在现代浏览器和Node.js中得到了很好的支持。可以像这样使用:

const matches = Array.from(myString.matchAll(/myRegEx/g)).map(match => match[1]);

请注意,传递的RegExp必须具有全局标志,否则将引发错误。
方便的是,当未找到匹配项时,这不会引发错误,因为.matchAll始终返回一个迭代器(而不是.match()返回null)。
对于这个具体的示例:
var input = "'Warehouse','Local Release','Local Release DA'";
var regex = /'(.*?)'/g;

var matches = Array.from(input.matchAll(regex)).map(match => match[1]);
// [ "Warehouse", "Local Release", "Local Release DA" ]

2
Array.from接受一个mapFn作为第二个参数。所以也可以这样做:Array.from(myString.matchAll(/myRegEx/g), m => m[1])。MDN在他们的matchAll文档中使用它作为一个例子,参见https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/matchAll。 - Melvin Roest

9

2
看起来这已经得到了很好的支持!太棒了! - derpedy-doo
1
没错:https://caniuse.com/?search=String.prototype.matchAll - shaedrich

5

由于JavaScript不支持向后查找,因此这不是非常通用的解决方案,但对于给定的输入,此正则表达式应该可以工作:

m = input.match(/([^',]+)(?=')/g);
//=> ["Warehouse", "Local Release", "Local Release DA"]

3

使用es2020,您可以使用matchAll

var input = "'Warehouse','Local Release','Local Release DA'";
var regex = /'(.*?)'/g;

const match_all = [...input.matchAll(regex)];

如果您使用TypeScript,请不要忘记在tsconfig.json中设置它:
"compilerOptions": {
    "lib": ["es2020.string"]
}

1
尝试使用input.replace(regex, "$1")之类的方法来获取捕获组的结果。

2
进入数组 - input.replace(regex, "$1").split(',') - levi
OP希望结果以数组形式返回。 - jfriend00
我喜欢你的思路,假设内容中没有逗号。 - Jondlm
@Jondlm 可以做 - regex = /'(.*?)'(,?)/g;input.replace(regex, "$1$2$2").split(',,') - levi

-1

这个正则表达式可以工作,但需要定义字符...

var input = "'Warehouse','Local Release','Local Release DA'";

var r =/'[\w\s]+'/gi;
console.log(input.match(regex));

1
这会在结果中保留单引号,这不是 OP 想要的。 - jfriend00

-2

编辑:这在JavaScript中不起作用,但在Java中可以。对此感到抱歉。

是的,它被称为“向前查看”“向后查看”

(?<=').*?(?=')
  • (?=') 向前查找 '
  • (?<=') 向后查找 '

在这里测试一下


在 JavaScript 中没有“向后查找”。 - Techsin
1
那么为什么还要写它,明知道它在Javascript中不起作用?否则人们会用Java标签来询问。真是难以置信... - Matt Fletcher
现在 JavaScript 中有“look behind”了。 - sunny-mittal
这是一篇关于如何使用回顾断言和前瞻断言的文章:https://v8.dev/blog/regexp-lookbehind-assertions - ikarasz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接