在数组中存储 JS 正则表达式捕获组的最佳方式?

Best way to store JS Regex capturing groups in array?

提问人:Fabrício Matté 提问时间:6/4/2012 最后编辑:YahkobFabrício Matté 更新时间:6/15/2016 访问量:11962

问:

正是标题所要求的。在解释我的问题时,我将提供一些示例。

测试字符串:

var test = "#foo# #foo# bar #foo#";

比如说,我想提取之间的所有文本(所有 s 但不是)。#foobar

var matches = test.match(/#(.*?)#/g);

如上所述,它将存储所有匹配项,但只会丢弃它看起来的捕获组。.match

var matches2 = /#(.*?)#/g.exec(test);

该方法显然只在数组的位置返回第一个结果的匹配字符串,而我在该位置中唯一捕获该匹配组。.exec01

我已经用尽了 SO、Google 和 MDN 寻找答案,但无济于事。

所以,我的问题是,有没有更好的方法来只存储匹配的捕获组,而不是循环访问并调用来存储捕获的组?.execarray.push

我对上述测试的预期数组应该是:

 [0] => (string) foo
 [1] => (string) foo
 [2] => (string) foo

接受纯 JS 和 jQuery 答案,如果您使用 .=]console.log

JavaScript 正则表达式

评论


答:

6赞 Aadit M Shah 6/4/2012 #1

我不确定这是否是您要找的答案,但您可以尝试以下代码:

var matches = [];

var test = "#foo# #foo# bar #foo#";

test.replace(/#(.*?)#/g, function (string, match) {
    matches.push(match);
});

alert(JSON.stringify(matches));

希望对你有所帮助。

评论

0赞 Fabrício Matté 6/4/2012
用于利用全局修饰符,这是一个非常甜蜜的技巧(比循环它更好,这是问题所在)。如果没有更好的选择,我现在会+1,并在睡觉前接受(将这个问题保留一段时间,因为它可能对将来的参考有用)。=].replace.exec
19赞 Prasenjit Kumar Nag 6/4/2012 #2

你可以使用 too like following 来构建一个数组.exec

var arr = [],
    s = "#foo# #bar# #test#",
    re = /#(.*?)#/g,
    item;

while (item = re.exec(s))
    arr.push(item[1]);

alert(arr.join(' '));​

工作小提琴

这里找到

好吧,它仍然有一个循环,如果你不想要一个循环,那么我认为你必须去.在这种情况下,代码将像.replace()

var arr = [];
var str = "#foo# #bar# #test#"
str.replace(/#(.*?)#/g, function(s, match) {
                           arr.push(match);
                        });

查看 MDN DOC 中的这些行,它解释了您关于如何更新属性的查询,execlastIndex

如果正则表达式使用“g”标志,则可以使用 exec 方法多次查找同一字符串中的连续匹配项。

执行此操作时,搜索将从 正则表达式的 lastIndex 属性(test 也将推进 lastIndex 属性)。

评论

0赞 Fabrício Matté 6/4/2012
类似于我发现的循环,但更加简化和优雅,看起来是一个合适的答案,因为我可以从数组中访问所有匹配项和捕获组。.execitem
0赞 Prasenjit Kumar Nag 6/4/2012
如果你想看更多的js魔法,你可以查看am-not-i-am的答案,它来自他的一个答案。:)
0赞 Fabrício Matté 6/4/2012
收藏了他的个人资料以稍后阅读答案 =] 现在,即使在通读了 MDN 文档之后,我也找不到每次调用时如何知道从哪里开始匹配字符串(“偏移量”?),嗯,重要的是它有效。我认为它会自动存储属性?如果有人可以发表评论,请这样做。.execlastIndex
0赞 Fabrício Matté 6/4/2012
哦,该死的伙计,我已经读过那段话的第一句话,但我不知何故错过了(一定是 SO fomatting x]),再次感谢!晚安。the search starts at the substring of str specified by the regular expression's lastIndex property (test will also advance the lastIndex property).
0赞 kennebec 6/4/2012 #3

另一个想法,虽然 exec 同样高效。

var s= "#foo# #foo# bar #foo#";
s= s.match(/#([^#])*#/g).join('#').replace(/^#+|#+$/g, '').split(/#+/);
2赞 Leonid 6/4/2012 #4

data.replace(/.*?#(.*?#)/g, '$1').split(/#/)
没有循环,没有函数。

评论

1赞 Aadit M Shah 6/15/2016
此外,输出错误。预期。实际。["foo", "foo", "foo"]["foo", "foo", "foo", ""]
0赞 Leonid 6/15/2016
@AaditMShah 是的,这是一个缺点 - 你总是必须弹出额外的东西。发现得很好。
0赞 Halo 9/25/2022
正确编辑了帖子
1赞 Erik Reppen 10/1/2014 #5

如果有人有与我类似的需求,我需要一个 Django 风格的 URL 配置处理程序的匹配函数,该处理程序可以将路径“参数”传递给控制器。我想出了这个。当然,如果匹配“$”,它不会很好地工作,但它不会在“$1.00”上中断。它比必要的更明确一点。您可以从 else 语句返回 matchedGroups,而不必打扰 for 循环测试,而是 ;;在循环中,声明有时会吓坏人们。

var url = 'http://www.somesite.com/calendar/2014/june/6/';
var calendarMatch = /^http\:\/\/[^\/]*\/calendar\/(\d*)\/(\w*)\/(\d{1,2})\/$/;

function getMatches(str, matcher){
    var matchedGroups = [];
    for(var i=1,groupFail=false;groupFail===false;i++){
        var group = str.replace(matcher,'$'+i);

        groupFailTester = new RegExp('^\\$'+i+'$');

        if(!groupFailTester.test(group) ){
            matchedGroups.push(group);
        }
        else {
            groupFail = true;
        }
    }
    return matchedGroups;
}

console.log( getMatches(url, calendarMatch) );