gpt4 book ai didi

javascript - 针对另一个对象的 JSON 递归值替换

转载 作者:搜寻专家 更新时间:2023-10-31 23:10:38 25 4
gpt4 key购买 nike

我有一个 json 对象,它由数组和带有一些占位符文本的映射组成,这些占位符文本可以通过传递另一个对象来替换。

例如。

data = {
"name": "Hello ${user.name}",
"primary_task": "Task Name: ${user.tasks[0].name}",
"secondary_tasks": ["Task 2: ${user.tasks[1].name}", "Task 2: ${user.tasks[2].name}"]
}

变量或元数据对象可以是

variables = {
"user": {
"name": "DJ"
},
"tasks": [
{
"name": "Task One"
}
]
}

我有一个函数可以根据某个对象获取字符串和字幕。我不确定如何递归地在 JSON 对象上调用它,以便它可以替换映射和数组中的所有字符串值

var data = {
"name": "Hello ${user.name}",
"primary_task": "Task Name: Task One",
"secondary_tasks": ["Task 2: ${user.tasks[1].name}", "Task 2: ${user.tasks[2].name}"]
}

var metadata = {
"user": {
"name": "DJ",
"tasks": [
{
"name": "Task One"
}
],
},
}

function subString(str) {
var rxp = /\{([^}]+)\}/g,
liveStr = str,
curMatch;

while( curMatch = rxp.exec( str ) ) {
var match = curMatch[1];
liveStr = liveStr.replace("${"+ match + "}", tryEval(match));
}
return liveStr;
}


function tryEval(evalStr) {
evalStr = "metadata." + evalStr;
try {
return eval(evalStr);
}
catch(error) {
return "${" + evalStr + "}";
}

}
var str = "user ${user.name} - ${user.tasks[0].name} - ${user.tasks[2].name}";

console.log("Sub " + subString(str));

在上面的例子中,${user.tasks[2].name} 在 meta 中不存在,因此它不应解析为未定义。如果在元对象中找不到 key ,它应该保持原样,即 ${user.tasks[2].name}

最佳答案

仅使用 ES6 的场景:

const data = { "name": "Hello ${user.name} ${user.foo}", "primary_task": "Task Name: ${user.tasks[0].name} ${user.tasks[10].name}", "secondary_tasks": ["Task 2: ${user.tasks[0].name}", "Task 2: ${user.tasks[1].name}", "Task 3: ${user.tasks[11].name}"] }
const meta = { "user": { "name": "DJ", "tasks": [ { "name": "Task One" }, { "name": "Task Two" } ] } }

const getPath = (path, obj) => path.split('.').reduce((r, c) =>
r ? c.includes('[') ? getPath(c.replace('[', '.').replace(']', ''), r) : r[c] : undefined, obj)

const interpolate = (s, v) =>
new Function(...Object.keys(v), `return \`${s}\`;`)(...Object.values(v))

const templ = (str, obj) => {
let r = new RegExp(/\${([\s\S]+?)}/g)
while (match = r.exec(str)) {
if (!getPath(match[1], obj))
str = str.replace(match[0], match[0].replace('${', '__'))
}
return interpolate(str, obj).replace('__', '${')
}

const resolve = (d, vars) => {
if (Array.isArray(d))
return d.map(x => templ(x, vars))
else
return Object.entries(d).reduce((r, [k, v]) =>
(r[k] = Array.isArray(v) ? resolve(v, vars) : templ(v, vars), r), {})
}

console.log(resolve(data, meta))

字符串插值思想受到 this thread 的影响.这个想法就是递归遍历所有对象值,使用interpolate函数返回实际的水合字符串。为了遍历路径,使用 getPath 以及发现不存在的路径。如果字符串中的路径不存在,则使用字符串替换来使该字符串通过字符串水合,然后我们替换回去。

Lodash _.template 场景:

在您可以使用 lodash 及其 templating mechanism 的场景中(通过 _.template)那么这个问题就变得更容易解决了,因为我们已经有了插值函数:

const data = { "name": "Hello ${user.name} ${user.foo}", "primary_task": "Task Name: ${user.tasks[0].name} ${user.tasks[10].name}", "secondary_tasks": ["Task 2: ${user.tasks[0].name}", "Task 2: ${user.tasks[1].name}", "Task 3: ${user.tasks[11].name}"] }
const meta = { "user": { "name": "DJ", "tasks": [ { "name": "Task One" }, { "name": "Task Two" } ] } }

const templ = (str, obj) => {
let r = new RegExp(/\${([\s\S]+?)}/g)
while (match = r.exec(str)) {
if (!_.get(obj, match[1]))
str = str.replace(match[0], match[0].replace('${', '__'))
}
return _.template(str)(obj).replace('__', '${')
}

const resolve = (d, vars) => {
if (_.isArray(d))
return _.map(d, x => templ(x, vars))
else
return _.entries(d).reduce((r, [k, v]) =>
(r[k] = _.isArray(v) ? resolve(v, vars) : templ(v, vars), r), {})
}

console.log(resolve(data, meta))
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>

这个想法是递归地遍历对象树并通过 lodash _.template 将任何简单属性转换为字符串。使用 Array.map_.map 遍历数组,使用 Array.reduce_.reduce遍历对象以将它们转换为模板字符串。

唯一的问题是要求保留不存在的路径。为了让它工作,我们检查哪条路径不存在,用 __ 替换它的 ${ ,当 _.template 函数完成水合时我们将其替换回的字符串。

关于javascript - 针对另一个对象的 JSON 递归值替换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53244193/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com