我想使用正则表达式匹配字符串的一部分,然后访问该带括号的子字符串:
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中返回"undefined"?.
问题是console.log
它的参数就像一个printf
语句,因为我正在记录的字符串("%A"
)有一个特殊的值,它试图找到下一个参数的值.
您可以像这样访问捕获组:
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]);
关于上面的多匹配括号示例,我在找不到我想要的内容之后在这里寻找答案:
var matches = mystring.match(/(?:neededToMatchButNotWantedInResult)(matchWanted)/igm);
在看了上面带有while和.push()的稍微复杂的函数调用之后,我突然意识到问题可以用mystring.replace()代替非常优雅(替换不是重点,甚至没有完成,CLEAN,第二个参数的内置递归函数调用选项是!):
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):
let reg = /#([\S]+)/igm; // Get hashtags.
let string = 'mi alegría es total! ?\n#fiestasdefindeaño #PadreHijo #buenosmomentos #france #paris';
let matches = (string.match(reg) || []).map(e => e.replace(reg, '$1'));
console.log(matches);
匹配表示对您的字符串运行RegEx模式的结果,如下所示:someString.match(regexPattern)
.
匹配模式表示输入字符串的所有匹配部分,它们都位于匹配数组内.这些都是输入字符串中模式的所有实例.
匹配组表示要捕获的所有组,在RegEx模式中定义.(括号内的模式,如下:/format_(.*?)/g
,哪里(.*?)
是匹配的组.)这些模式位于匹配的模式中.
要访问匹配的组,在每个匹配的模式中,您需要一个函数或类似的东西来迭代匹配.正如许多其他答案所示,有很多方法可以做到这一点.大多数其他答案使用while循环来迭代所有匹配的模式,但我想我们都知道这种方法的潜在危险.有必要匹配一个new RegExp()
而不仅仅是模式本身,只在评论中提到.这是因为该.exec()
方法的行为类似于生成器函数 - 它在每次匹配时停止,但.lastIndex
在下次.exec()
调用时保持其继续.
下面是一个函数的一个例子searchString
,它返回一个Array
所有的匹配的模式,其中每一个match
是一个Array
与所有的含有匹配组.我没有使用while循环,而是提供了使用Array.prototype.map()
函数和更for
高效的方法的示例- 使用plain -loop.
这些性能较差,因为它们基本上实现了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
我还没有将这些替代方法与之前在其他答案中提到的方法进行比较,但我怀疑这种方法的性能较差,而且其他方法的安全性较低.
你的语法可能不是最好的.FF/Gecko将RegExp定义为Function的扩展.
(FF2竟然typeof(/pattern/) == 'function'
)
这似乎是特定于FF - IE,Opera和Chrome都为它抛出异常.
相反,使用其他人先前提到的方法:RegExp#exec
或String#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"]
无需调用该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具有在括号中隔离的第二个匹配.嵌套括号很棘手,所以要小心!
String#matchAll
(see the Stage 3 Draft / December 7, 2018 proposal), simplifies acccess to all groups in the match object (mind that Group 0 is the whole match, while further groups correspond to the capturing groups in the pattern):
With
matchAll
available, you can avoid thewhile
loop andexec
with/g
... Instead, by usingmatchAll
, you get back an iterator which you can use with the more convenientfor...of
, array spread, orArray.from()
constructs
This method yields a similar output to Regex.Matches
in C#, re.finditer
in Python, preg_match_all
in PHP.
See a JS demo (tested in Google Chrome 73.0.3683.67 (official build), beta (64-bit)):
var myString = "key1:value1, key2-value2!!@key3=value3";
var matches = myString.matchAll(/(\w+)[:=-](\w+)/g);
console.log([...matches]); // All match with capturing group values
只有在您有一对括号时才能使用的单线程:
while ( ( match = myRegex.exec( myStr ) ) && matches.push( match[1] ) ) {};
使用你的代码:
console.log(arr[1]); // prints: abc console.log(arr[0]); // prints: format_abc
编辑:Safari 3,如果重要的话.
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);
使用es2018,您现在可以String.match()
使用命名组,使您的正则表达式更加明确地说明其尝试执行的操作。
const url = '/sf/ask/17360801/?some=parameter'; const regex = /(?https?):\/\/(? [\w-\.]*)\/(? [\w-\./]+)\??(? .*?)?$/; const { groups: segments } = url.match(regex); console.log(segments);
你会得到像
{协议:“ https”,主机名:“ stackoverflow.com”,路径名:“ questions / 432493 / how-do-you-access-the-matched-groups-in-javascript-regular-expression”,查询字符串:“ some = parameter“}