【问题标题】:Change object key names won't accept replacing dots更改对象键名不接受替换点
【发布时间】:2021-06-25 09:45:06
【问题描述】:

我有一个 JSON 对象,它的键名中有点。我需要用“DOT”替换这些点(例如)。

    {
        "key1.key": "merciful",
        "key2": {
            "key2.key": "grateful"
        }
    }

所以,key1.key 转换为 key1DOTkey

使用Change key name in nested JSON structure 中建议的方法,我使用了 JSON.Parse 的reviver parameter,它可以像一个魅力一样替换键名中的任何内容,除了点:替换点时,它会截断对象。

此代码替换所有“e”并且工作正常

var parseE = JSON.parse(obj, function (k, v) {
    if (k.search(".") != -1)
       this[k.replace(/e/g, 'DOT')] = v;
    else
        return v;
});

返回

{
    "kDOTy1.kDOTy": "merciful",
    "kDOTy2": {
        "kDOTy2.kDOTy": "grateful"
    }
}

但是如果我尝试替换点“.”,那么对象会被截断

var parseDOT = JSON.parse(obj, function (k, v) {
    if (k.search(".") != -1)
       this[k.replace(/\./g, 'DOT')] = v;
    else
        return v;
});

返回第一个键值对,很好地替换,但没有别的:

{
    "key1DOTkey": "merciful"
}

我尝试过使用replaceAll,甚至创建了一个函数来一一替换字符以避免使用正则表达式,以防万一。没什么,同样的结果。

这是一个小提琴:https://jsfiddle.net/dpiret/dgk5fp16/7/

注意:替换字符串对象中的所有点对我不起作用,因为它也会替换值中的点。

如果有任何指示,我将不胜感激

【问题讨论】:

    标签: javascript object parsing


    【解决方案1】:

    search 使用正则表达式(所以. 匹配任何字符!),只需使用字符串方法,如indexOf

    var obj = `{
        "key1.key": "merciful",
        "key2": {
            "key2.key": "grateful"
        },
        "key3": {
            "key3.keyA.keyB": "thankful"
        }
    }`
    var parseDOT = JSON.parse(obj, function (k, v) {
        let key = k;
        if (key.indexOf(".") != -1){
           while(key.indexOf(".") != -1)
              key = key.replace(".","DOT");
           this[key] = v;
        }
        else
            return v;
    });
    console.log(parseDOT)

    很抱歉,我很难解释为什么上述方法有效。我可以告诉你的是你的原始解决方案匹配了 every 键 - 不清楚的是为什么它不只是更新每个属性,而不是那些没有点的人。

    【讨论】:

    • 解释一下为什么parsesearch 结合使用会失败。
    • @georg 你是对的,它会的。我只是有点困惑。在得出原因之前,我已经找到了解决方案。
    • 是的,我也想了一些。我猜原因是,它们从第一个分支返回undefined,从而告诉解析器删除密钥k。由于key2.replace(/./. DOT) 仍然是key2,因此分配是空操作并且密钥被删除。又一个 javascript wtf 时刻......
    • @georg 我比你晚了大约 2 分钟,我想我只是想知道发生了什么
    • @danielp 查看更新后的答案 - 您可以简单地使用 while 来继续替换点,直到不再有替代点 replaceAll (我相当确定 replaceAll 在引擎盖!)
    【解决方案2】:

    替换将起作用 - 这个不会触及值

    const str = `{
        "key1.key": "merciful",
        "key2": {
            "key2.key": "grateful.dead"
        },
        "key3": {
            "key3.key.key": "text.text"
        }
    }`
    const str1 = str.replace(/"(\w+\.\w+)+":/g,function(match) { return match.replace(/\./g,"DOT")})
    const obj = JSON.parse(str1);
    console.log(obj);

    检查 "text.text": 作为值

    const str = `{
        "key1.key": "merciful",
        "key2": {
            "key2.key": "grateful.dead"
        },
        "key3": {
            "key3.key.key": "text.text"
        }
    }`
    
    const obj = JSON.parse(str);
    console.log(obj);
    obj["key3"]["key3.key.key"] = `"text.text":`
    
    console.log(obj);
    
    let str1 = JSON.stringify(obj)
    
    console.log(str1);
    
    str1 = str1.replace(/"(\w+\.\w+)+":/g,function(match) { return match.replace(/\./g,"DOT")})
    
    console.log(str1);
    
    const obj1 = JSON.parse(str1)
    
    console.log(obj1)

    【讨论】:

    • 如果点不在属性名称中怎么办?
    • 谢谢,@mplungjan。这行得通。我试图避免这种基于引号和冒号识别键名的方法,但我猜它适用于 99% 的情况,即值中没有像 "text": 这样的部分。我考虑的另一个选择是使用递归函数对对象进行深层复制,在需要的地方替换名称。但这似乎有点矫枉过正,性能很重要。
    • JSON 字符串在值中不会有任何“文本”:。它们将被转义并看起来像 "\"text\":" 而不会被我的正则表达式拾取 - 请参阅我编写的测试
    • 你说得对,@mplungjan。使用您的解决方案并且工作得很好。谢谢!
    猜你喜欢
    • 1970-01-01
    • 2017-03-15
    • 2019-02-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-12
    相关资源
    最近更新 更多