如何访问JavaScript正则expression式中的匹配组?

我想用一个正则expression式来匹配string的一部分,然后访问那个被括起来的子string:

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 (!!!) 

我究竟做错了什么?


我发现上面的正则expression式代码没有错:我testing的实际string是这样的:

 "date format_%A" 

报告“%A”未定义似乎是一个非常奇怪的行为,但它不是直接关系到这个问题,所以我打开了一个新的, 为什么匹配的子string在JavaScript中返回“undefined”?


问题是, console.log的参数就像一个printf语句,由于我logging的string( "%A" )有一个特殊的值,它试图find下一个参数的值。

您可以像这样访问捕获组:

 var myString = "something format_abc"; var myRegexp = /(?:^|\s)format_(.*?)(?:\s|$)/g; var match = myRegexp.exec(myString); console.log(match[1]); // abc 

这里有一个方法可以用来获得每个匹配的第n个捕获组:

 function getMatches(string, regex, index) { index || (index = 1); // default to the first capturing group var matches = []; var match; while (match = regex.exec(string)) { matches.push(match[index]); } return matches; } // Example : var myString = 'something format_abc something format_def something format_ghi'; var myRegEx = /(?:^|\s)format_(.*?)(?:\s|$)/g; // Get an array containing the first capturing group for every match var matches = getMatches(myString, myRegEx, 1); // Log results document.write(matches.length + ' matches found: ' + JSON.stringify(matches)) console.log(matches); 
 var myString = "something format_abc"; var arr = myString.match(/\bformat_(.*?)\b/); console.log(arr[0] + " " + arr[1]); 

你的语法可能不是最好的。 FF / Gecko将RegExp定义为Function的扩展。
(FF2走到了typeof(/pattern/) == 'function'

看来这是特定于FF – IE,Opera和Chrome都会抛出exception。

而是使用前面提到的其他方法: RegExp#execString#match
他们提供了相同的结果:

 var regex = /(?:^|\s)format_(.*?)(?:\s|$)/; var input = "something format_abc"; regex(input); //=> [" format_abc", "abc"] regex.exec(input); //=> [" format_abc", "abc"] input.match(regex); //=> [" format_abc", "abc"] 

关于上面的多重匹配括号的例子,在我没有得到我想要的东西之后,我在这里寻找答案:

 var matches = mystring.match(/(?:neededToMatchButNotWantedInResult)(matchWanted)/igm); 

用上面的while和.push()函数调用稍微复杂的函数后,发现问题可以用mystring.replace()很好地解决(replace不是重点,甚至没有完成,CLEAN,第二个参数的内置recursion函数调用选项是!):

 var yourstring = 'something format_abc something format_def something format_ghi'; var matches = []; yourstring.replace(/format_([^\s]+)/igm, function(m, p1){ matches.push(p1); } ); 

在这之后,我不认为我会永远不会再使用.match()。

最后但并非最不重要的是,我发现一行代码适用于我(JS ES6):

 var reg = /#([\S]+)/igm; //get hashtags var string = 'mi alegría es total! ✌🙌\n#fiestasdefindeaño #PadreHijo #buenosmomentos #france #paris'; var matches = string.match(reg).map(e => e.replace(reg, '$1')); console.log(matches); 

只有在有一对括号的情况下才有实际意义:

 while ( ( match = myRegex.exec( myStr ) ) && matches.push( match[1] ) ) {}; 

使用你的代码:

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

编辑:Safari 3,如果它很重要。

你的代码适用于我(Mac上的FF3),即使我同意PhiLo的正则expression式可能应该是:

 /\bformat_(.*?)\b/ 

(但是,当然,我不确定,因为我不知道正则expression式的上下文。)

 function getMatches(string, regex, index) { index || (index = 1); // default to the first capturing group var matches = []; var match; while (match = regex.exec(string)) { matches.push(match[index]); } return matches; } // Example : var myString = 'Rs.200 is Debited to A/c ...2031 on 02-12-14 20:05:49 (Clear Bal Rs.66248.77) AT ATM. TollFree 1800223344 18001024455 (6am-10pm)'; var myRegEx = /clear bal.+?(\d+\.?\d{2})/gi; // Get an array containing the first capturing group for every match var matches = getMatches(myString, myRegEx, 1); // Log results document.write(matches.length + ' matches found: ' + JSON.stringify(matches)) console.log(matches); 

没有必要调用exec方法! 您可以直接在string上使用“匹配”方法。 只是不要忘记括号。

 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包含所有结果的string。 位置1的第一个匹配用圆括号表示,位置2的第二个匹配用圆括号括起来。 嵌套括号是棘手的,所以要小心!

在这个答案中使用的术语:

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

描述

要访问匹配的组 ,在每个匹配模式中 ,需要一个函数或类似的东西来遍历匹配 。 有很多方法可以做到这一点,就像许多其他的答案一样。 大多数其他答案使用while循环遍历所有匹配的模式 ,但我认为我们都知道这种方法的潜在危险。 有必要匹配一个new RegExp()而不是模式本身,只有在评论中提到。 这是因为.exec()方法的行为类似于生成器函数 – 每次匹配时都会停止 ,但在下一个.exec()调用时保持它的.lastIndex继续。

代码示例

下面是一个函数searchString的例子,它返回一个所有匹配模式Array ,每个match是一个包含所有包含匹配组Array 。 我没有使用while循环,而是使用Array.prototype.map()函数以及更高性能的方式提供了示例 – 使用plain for -loop。

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

这些性能较差,因为它们基本上实现了for 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 

高性能版本(更多的代码,更less的语法糖)

 // 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 

我还没有将这些替代scheme与其他答案中提到的替代方法进行比较,但是我怀疑这种方法的性能不如其他方法高。

 /*Regex function for extracting object from "window.location.search" string. */ var search = "?a=3&b=4&c=7"; // Example search string var getSearchObj = function (searchString) { var match, key, value, obj = {}; var pattern = /(\w+)=(\w+)/g; var search = searchString.substr(1); // Remove '?' while (match = pattern.exec(search)) { obj[match[0].split('=')[0]] = match[0].split('=')[1]; } return obj; }; console.log(getSearchObj(search)); 

看看第12课的这个链接 :

您可以使用特殊() (括号)对字符进行分组。 要捕获图像文件,请写下expression式^(IMG(\d+))\.png$