javascript正则表达式解析数组语法字符串几乎正常工作

时间:2017-06-15 19:55:30

标签: javascript arrays regex url

所以我正在解析具有类似数组语法的字符串(来自URL),例如:

variable[foo]
variable[foo][bar]

我需要每个索引(在方括号中)作为它自己的捕获组,我需要它来处理一个OR MORE索引...我的正则表达式ALMOST工作,但只捕获FINAL索引而不是正在进行的那些,所以用一个指数就可以完美。

here您可以看到我的最佳尝试,当您将鼠标悬停在第二个示例上时,您会看到group_4成为捕获的第2组,其余的则丢失。我需要捕获的组匹配示例名称。

只是为了好的衡量,在这里你可以看到我将整个正则表达式结果解析为实际javascript对象的整个解决方案。

getUrlParams: function() {
        let query = decodeURIComponent(window.location.search);

        let paramRegex = /[&?]([\w[\]\-%]+)=([\w[\]\-%/,\s]+)(?=&|$)/igm;
        let arrayRegex = /([\w]+)(?:(?:\[|%5B)([\w]+)(?:]|%5D))+/igm;

        let params = {};

        let match = paramRegex.exec(query);
        while (match !== null) {
            if (match && match[1]) {

                let array = arrayRegex.exec(match[1]);
                while(array !== null) {
                    if (array && array[1] && array[2]) {
                        console.log("ARRAY: ", array);
                         let deepParam = {};
                         deepParam[array[2]] = match[2];
                         if (array[1] in params) {
                             $.extend(params[array[1]], deepParam);
                         } else {
                             params[array[1]] = deepParam;
                         }
                    } else {
                        params[match[1]] = match[2];
                    }

                    array = arrayRegex.exec(match[1]);
                }
            }
            match = paramRegex.exec(query);
        }
        return params;
    },

此代码仅适用于一个索引,但一旦正则表达式捕获多个索引,此代码也必须处理它。

非常感谢任何帮助。

更新:

这是我的最终功能解决方案,基于bowheart非常优雅的代码。

    getUrlParams: function() {
    let query = decodeURIComponent(window.location.search);
    let paramRegex = /[&?]([\w[\]\-%]+)=([\w[\]\-%/,\s]+)(?=&|$)/igm;

    let params = {};

    let match = paramRegex.exec(query);
    while (match !== null) {
        if (match && match[1] && match[2]) {
            let key = match[1];
            let val = match[2];
            let arrayKeys = key.split(/\[|]/g).filter(node => node);
            populateObject(params, arrayKeys, val);

        }
        match = paramRegex.exec(query);
    }

    return params;

    function populateObject(obj, keys, val) {
        if (keys.length === 1) return obj[keys[0]] = (isNaN(+val) ? val : +val);
        let nextKey = keys.shift();
        if (!obj[nextKey]) obj[nextKey] = isNaN(+keys[0]) ? {} : [];

        populateObject(obj[nextKey], keys, val);
    }
},

3 个答案:

答案 0 :(得分:1)

试试这个正则表达式:

(?:[\?|\&]([\w]+))|((?:\[|%5B)(\w+)(?:]|%5D))

它将每个组值捕获为独立匹配

答案 1 :(得分:1)

究竟是什么让你想到用两个大规模的正则表达式完成所有这些?只是......不要这样做。你可能会活得更久。你需要在某种程度上使用正则表达式,但始终保持尽可能短。

如果您有兴趣,这是一个解决方案。你会发现它更短,更容易阅读,并完成所有要求:

// Recursively populates nested objects/arrays.
function populateObj(obj, keys, val) {
    if (keys.length === 1) return obj[keys[0]] = val

    let nextKey = keys.shift()
    if (!obj[nextKey]) obj[nextKey] = isNaN(+keys[0]) ? {} : []

    populateObj(obj[nextKey], keys, val)
}

let params = {}
let search = '?filters[name]=sa&filters[group_2][group_3][group_4]=4&order_bys[0][field]=name&order_bys=desc'

search.slice(1).split('&').forEach(pair => {
    let [key, val] = pair.split('=')
    key = key.split(/\[|]/g).filter(node => node)
    populateObj(params, key, val)
})

// Just for display:
document.body.innerHTML = JSON.stringify(params, null, ' &nbsp;').replace(/\n/g, '<br>')

基本算法是:

  • '&'上拆分GET参数,然后将每个参数拆分为'='上的一个键值对。

  • 正则表示键中的任何方括号,以获取嵌套数组/对象的所有节点。

  • 递归遍历一个对象,必要时创建子对象/数组,并将给定值分配给最后一个节点。

    • 如果下一个键是数字,则创建一个数组。否则,创建一个对象。

(请注意您的regexr代码段order_bys[0][field]=nameorder_bys=desc参数不兼容,因为其中一个表示order_bys是零索引数组,另一个表示它是一个字符串。不确定在哪里你有那些数据......)。

答案 2 :(得分:0)

在方括号上拆分并过滤掉空字符串:

"variable[foo][bar]".split(/\]|\[/).filter(s => !!s)
> [ "variable", "foo", "bar" ]