如何在JavaScript正则表达式中访问匹配的组?

我想使用正则表达式匹配字符串的一部分,然后访问带括号的子字符串:

var myString = "something format_abc"; // I want "abc"

var arr = /(?:^|\s)format_(.*?)(?:\s|$)/.exec(myString);

console.log(arr);     // Prints: [" format_abc", "abc"] .. so far so good.
console.log(arr[1]);  // Prints: undefined  (???)
console.log(arr[0]);  // Prints: format_undefined (!!!)

我究竟做错了什么?


我发现上面的正则表达式代码没有任何问题:我要针对的实际字符串是:

"date format_%A"

报告“%A”未定义似乎是一个非常奇怪的行为,但与该问题没有直接关系,因此我打开了一个新的代码,为什么匹配的子字符串在JavaScript中返回“未定义”?


问题在于console.log它的参数就像一条printf语句一样,并且由于我正在记录的字符串("%A")具有特殊值,因此它试图查找下一个参数的值。

A猪猪2020/03/09 21:31:22

We can access the matched group in a regular expressions by using backslash followed by number of the matching group:

/([a-z])\1/

In the code \1 represented matched by first group ([a-z])

GilJinJin2020/03/09 21:31:22

Get all group occurrence

let m=[], s = "something format_abc  format_def  format_ghi";

s.replace(/(?:^|\s)format_(.*?)(?:\s|$)/g, (x,y)=> m.push(y));

console.log(m);

Davaid阳光伽罗2020/03/09 21:31:22

仅当您有一对括号时,一个内衬才实用:

while ( ( match = myRegex.exec( myStr ) ) && matches.push( match[1] ) ) {};
伽罗Tony小卤蛋2020/03/09 21:31:22

无需调用该exec方法!您可以直接在字符串上使用“ match”方法。只是不要忘记括号。

var str = "This is cool";
var matches = str.match(/(This is)( cool)$/);
console.log( JSON.stringify(matches) ); // will print ["This is cool","This is"," cool"] or something like that...

位置0有一个包含所有结果的字符串。位置1的第一个匹配项用括号表示,位置2的第二个匹配项用括号括起来。嵌套括号很棘手,所以要当心!

满天星2020/03/09 21:31:22

使用您的代码:

console.log(arr[1]);  // prints: abc
console.log(arr[0]);  // prints:  format_abc

编辑:Safari 3,如果有关系。

TonyStafan2020/03/09 21:31:22

String#matchAll(请参阅第3阶段草案/ 2018年12月7日提案),简化了比赛对象中所有小组的出入率(请注意,小组0是整个比赛,而其他小组则对应于模式中的捕获小组):

使用matchAllavailable可以避免while循环,exec/g... 可以通过使用来matchAll获得迭代器,该迭代器可以与更方便的for...ofarray spreadArray.from()构造一起使用

此方法产生的输出类似于Regex.MatchesC#,re.finditerPython,preg_match_allPHP的输出。

查看JS演示(已在Google Chrome 73.0.3683.67(官方版本)中进行测试,测试版(64位)):

var myString = "key1:value1, key2-value2!!@key3=value3";
var matches = myString.matchAll(/(\w+)[:=-](\w+)/g);
console.log([...matches]); // All match with capturing group values

console.log([...matches])节目

在此处输入图片说明

您还可以使用以下方式获取匹配值或特定的组值:

let matchData = "key1:value1, key2-value2!!@key3=value3".matchAll(/(\w+)[:=-](\w+)/g)
var matches = [...matchData]; // Note matchAll result is not re-iterable

console.log(Array.from(matches, m => m[0])); // All match (Group 0) values
// => [ "key1:value1", "key2-value2", "key3=value3" ]
console.log(Array.from(matches, m => m[1])); // All match (Group 1) values
// => [ "key1", "key2", "key3" ]

注意:请参阅浏览器兼容性详细信息。

小宇宙猴子2020/03/09 21:31:22

此答案中使用的术语:

  • Match表示对字符串运行RegEx模式的结果,如下所示:someString.match(regexPattern)
  • 匹配的模式指示输入字符串的所有匹配部分,它们全部位于match数组内。这些都是输入字符串中模式的所有实例。
  • 匹配的组指示在RegEx模式中定义的所有要捕获的组。(括号内的模式,如下所示:/format_(.*?)/g,其中(.*?)将是一个匹配的组。)它们位于匹配的模式内

描述

To get access to the matched groups, in each of the matched patterns, you need a function or something similar to iterate over the match. There are a number of ways you can do this, as many of the other answers show. Most other answers use a while loop to iterate over all matched patterns, but I think we all know the potential dangers with that approach. It is necessary to match against a new RegExp() instead of just the pattern itself, which only got mentioned in a comment. This is because the .exec() method behaves similar to a generator functionit stops every time there is a match, but keeps its .lastIndex to continue from there on the next .exec() call.

Code examples

下面是一个函数示例,该函数searchString返回Array所有匹配模式的,其中每个match,其中Array包含所有匹配的组我没有使用while循环,而是提供了使用Array.prototype.map()函数以及更for高效的方法的示例-使用纯循环。

简洁的版本(更少的代码,更多的语法糖)

由于它们基本上实现了forEach-loop而不是更快的for-loop ,因此它们的性能较低

// Concise ES6/ES2015 syntax
const searchString = 
    (string, pattern) => 
        string
        .match(new RegExp(pattern.source, pattern.flags))
        .map(match => 
            new RegExp(pattern.source, pattern.flags)
            .exec(match));

// Or if you will, with ES5 syntax
function searchString(string, pattern) {
    return string
        .match(new RegExp(pattern.source, pattern.flags))
        .map(match =>
            new RegExp(pattern.source, pattern.flags)
            .exec(match));
}

let string = "something format_abc",
    pattern = /(?:^|\s)format_(.*?)(?:\s|$)/;

let result = searchString(string, pattern);
// [[" format_abc", "abc"], null]
// The trailing `null` disappears if you add the `global` flag

性能版本(更多代码,更少语法糖)

// Performant ES6/ES2015 syntax
const searchString = (string, pattern) => {
    let result = [];

    const matches = string.match(new RegExp(pattern.source, pattern.flags));

    for (let i = 0; i < matches.length; i++) {
        result.push(new RegExp(pattern.source, pattern.flags).exec(matches[i]));
    }

    return result;
};

// Same thing, but with ES5 syntax
function searchString(string, pattern) {
    var result = [];

    var matches = string.match(new RegExp(pattern.source, pattern.flags));

    for (var i = 0; i < matches.length; i++) {
        result.push(new RegExp(pattern.source, pattern.flags).exec(matches[i]));
    }

    return result;
}

let string = "something format_abc",
    pattern = /(?:^|\s)format_(.*?)(?:\s|$)/;

let result = searchString(string, pattern);
// [[" format_abc", "abc"], null]
// The trailing `null` disappears if you add the `global` flag

我还没有将这些替代方案与其他答案中先前提到的替代方案进行比较,但是我怀疑这种方法与其他方法相比,其性能和故障安全性更低。

Eva卡卡西2020/03/09 21:31:22

var myString = "something format_abc";
var arr = myString.match(/\bformat_(.*?)\b/);
console.log(arr[0] + " " + arr[1]);

\b不是一回事。(它适用于--format_foo/,但不适用format_a_b),但我想展示一种替代您的表情的方法,这很好。当然,match通话是重要的。