【问题标题】:Best way to store JS Regex capturing groups in array?将 JS 正则表达式捕获组存储在数组中的最佳方法?
【发布时间】:2012-06-04 04:31:07
【问题描述】:

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

测试字符串:

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

说,我想提取#之间的所有文本(所有foos,但不是bar)。

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

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

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

.exec 方法显然只返回数组的位置 0 中第一个结果的匹配字符串,以及位置 1 中我唯一捕获该匹配的组。

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

那么,我的问题是,有没有比使用.exec 循环并调用array.push 来存储捕获的组更好的方法来仅存储匹配的捕获组?

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

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

接受纯 JS 和 jQuery 答案,如果您使用 console.log 发布 JSFiddle,则需要额外的 cookie。 =]

【问题讨论】:

    标签: javascript regex


    【解决方案1】:

    你也可以像下面这样使用.exec来构建一个数组

    var arr = [],
        s = "#foo# #bar# #test#",
        re = /#(.*?)#/g,
        item;
    
    while (item = re.exec(s))
        arr.push(item[1]);
    
    alert(arr.join(' '));​
    

    Working Fiddle

    Here找到

    嗯,它仍然有一个循环,如果你不想要一个循环,那么我认为你必须使用.replace()。在这种情况下,代码将类似于

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

    查看MDN DOC 中的这些行,这解释了您对exec 如何更新lastIndex 属性的查询,我认为,

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

    当你这样做时,搜索从 str 指定的子字符串开始 正则表达式的 lastIndex 属性(测试也会提前 lastIndex 属性)。

    【讨论】:

    • 与我发现的 .exec 循环类似,但更加简化和优雅,看起来是一个合适的答案,因为我可以从 item 数组中访问所有匹配项和捕获组。
    • 如果你想看更多的js魔法可以查看am-not-i-am的答案,来自他的一个答案。 :)
    • 收藏了他的配置文件以便稍后阅读答案 =] 现在,即使在阅读了 MDN Documentation 之后,我也无法找到 .exec 如何知道从哪里开始匹配字符串(“偏移量“?)每次调用它时,重要的是它可以工作。我认为它会自动存储lastIndex 属性?如果有人可以发表评论,请这样做。 =]
    • 天哪,我已经阅读了该段的第一句话,但不知何故错过了the search starts at the substring of str specified by the regular expression's lastIndex property (test will also advance the lastIndex property).(它必须是SO fomatting x]),再次感谢!晚安。
    【解决方案2】:

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

    var matches = [];
    
    var test = "#foo# #foo# bar #foo#";
    
    test.replace(/#(.*?)#/g, function (string, match) {
        matches.push(match);
    });
    
    alert(JSON.stringify(matches));

    希望对你有帮助。

    【讨论】:

    • 使用.replace 来利用全局修饰符,这是一个非常好的技巧(比使用.exec 循环更好,这是问题所在)。如果没有更好的选择,我现在会 +1 并在睡觉前接受(保持这个问题开放一段时间,因为它可能对将来的参考有用)。 =]
    【解决方案3】:

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

    【讨论】:

    • 另外,输出错误。预期["foo", "foo", "foo"]。实际["foo", "foo", "foo", ""].
    • @AaditMShah 是的,这是一个缺点 - 你总是不得不弹出额外的。很好发现。
    【解决方案4】:

    如果有人有类似的需求,我需要一个 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) );
    

    【讨论】:

      【解决方案5】:

      另一种想法,虽然 exec 效率一样。

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

      【讨论】:

        猜你喜欢
        • 2011-01-19
        • 2015-07-24
        • 2021-08-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多