如何从 JSON 兼容的嵌套 object/data-structure 中递归生成类似标记的字符串?
How does one recursively generate a markup-like string from a JSON-compatible nested object/data-structure?
let json = {
"user": {
"first_name": "test",
"second_name": "second name",
"profile": {
"test":{
"img": "img"
}
}
},
"company": {
"name": "company 1",
"company_nested": {
"test" : "test"
}
}
}
let new_json = "";
function iterate(obj) {
Object.keys(obj).forEach((key, index) => {
let value = obj[key];
if(typeof value === 'string') {
new_json += `"${key}": ${value}\n`;
}
if (typeof value === 'object') {
new_json +=`##${key}##\n`;
iterate(value);
}
});
}
iterate(json);
$("#teste").html(new_json);
结果
##user##
"first_name": test
"second_name": second name
##profile##
##test##
"img": img
有没有更好的方法来更改我想要的东西(自定义的)的大括号?
- 左括号 ({) 必须是 ##KEY_NAME##
- 括号 (}) 必须是 ##/KEYNAME##
期望的结果
##user##
"first_name": test
"second_name": second name
##profile##
##test##
"img": img
##/test##
##/profile##
##/user##
##company##
"name": company 1
##company_nested##
"test": test
##/company_nested##
##/company##
您可以遍历对象的条目。如果 values 是一个对象,则递归调用函数并将对象包装在 ##${k}##
和 ##/${k}##
中
const input={user:{first_name:"test",second_name:"second name",profile:{test:{img:"img"}}},company:{name:"company 1",company_nested:{test:"test"}}};
function replace(o) {
return Object.entries(o).map(([k, v]) => {
if (typeof v === 'object')
return `##${k}##
${replace(v)}
##/${k}##`
else
return `"${k}": ${v}`
}).join("\n")
}
console.log(replace(input))
如果多行模板文字难以阅读,您可以创建一个数组并使用 join
:
const replace = o =>
Object.entries(o).map(([k, v]) =>
typeof v === 'object'
? [`##${k}##`, replace(v), `##/${k}##`].join('\n')
: `"${k}": ${v}`
).join("\n")
我假设您的 json 格式正确。如果没有,您可能需要在代码中处理。
第 1 步:将您的 json 转换为字符串。
let str = JSON.stringify(json);
第 2 步:创建一个符号映射,将现有符号作为键,将新符号作为值。
let symbolMap = new Map();
symbolMap.set("{", "$");
symbolMap.set("}", "%");
迭代字符串中的每个字符,检查字符是否存在于映射中,如果存在,则替换新值。
for (let i = 0; i < str.length; i++) {
if (symbolMap.get(str[i])) {
str = str.replace(str[i], symbolMap.get(str[i]));
}
}
打印输出
console.log(str);
输出:
之前:
{"user":{"first_name":"test","second_name":"second name","profile":{"test":{"img":"img"}}},"company":{"name":"company 1","company_nested":{"test":"test"}}}
之后:
$"user":$"first_name":"test","second_name":"second name","profile":$"test":$"img":"img"%%%,"company":$"name":"company 1","company_nested":$"test":"test"%%%
完整代码:
let json = {
user: {
first_name: "test",
second_name: "second name",
profile: {
test: {
img: "img",
},
},
},
company: {
name: "company 1",
company_nested: {
test: "test",
},
},
};
let str = JSON.stringify(json);
let symbolMap = new Map();
symbolMap.set("{", "$");
symbolMap.set("}", "%");
console.log(str);
for (let i = 0; i < str.length; i++) {
if (symbolMap.get(str[i])) {
str = str.replace(str[i], symbolMap.get(str[i]));
}
}
console.log(str);
此方法基于单个递归调用的 reduce
r 函数。它也是一个通用的标记生成解决方案,因为它可以通过 reducer 函数的第一个参数进行配置 ...
function createCustomMarkupRecursively(collector, [key, value], idx) {
collector.config = collector.config || {};
collector.level = collector.level || 0;
const {
markup = '',
config: {
quote = '"',
prefix = '##', suffix = '##',
terminator = '/', separator = '\n',
},
} = collector;
const markupBlockSeparator = ((collector.level === 0) && (idx > 0))
? separator
: '';
if (value && (typeof value === 'object')) {
++collector.level;
collector.markup = [
markup,
markupBlockSeparator,
`${ prefix }${ key }${ suffix }\n`,
Object.entries(value).reduce(
createCustomMarkupRecursively,
Object.assign(collector, { markup: ''}),
).markup,
`${ prefix }${ terminator }${ key }${ suffix }\n`,
].join('');
--collector.level;
} else {
collector.markup = [
markup,
markupBlockSeparator,
quote,
key,
quote,
`: ${ value }\n`,
].join('');
}
return collector;
}
const data = {
user: {
first_name: "test",
second_name: "second name",
profile: {
test: {
img: "img",
},
},
},
company: {
name: "company 1",
company_nested: {
test : "test",
},
},
};
const { markup } = Object
.entries(data)
.reduce(createCustomMarkupRecursively, {/*
config: {
quote: '"',
prefix: '##',
suffix: '##',
terminator: '/',
separator: '\n'
},*/
markup: '',
});
// according to the OP ...
console.log(markup);
// customization sample ...
console.log(
Object
.entries(data)
.reduce(createCustomMarkupRecursively, {
config: {
quote: "'",
prefix: '<',
suffix: '>',
terminator: '$',
separator: '\n<-- // -->\n\n',
},
markup: '## another markup configuration result ##\n\n',
}).markup
)
.as-console-wrapper { min-height: 100%!important; top: 0; }
let json = {
"user": {
"first_name": "test",
"second_name": "second name",
"profile": {
"test":{
"img": "img"
}
}
},
"company": {
"name": "company 1",
"company_nested": {
"test" : "test"
}
}
}
let new_json = "";
function iterate(obj) {
Object.keys(obj).forEach((key, index) => {
let value = obj[key];
if(typeof value === 'string') {
new_json += `"${key}": ${value}\n`;
}
if (typeof value === 'object') {
new_json +=`##${key}##\n`;
iterate(value);
}
});
}
iterate(json);
$("#teste").html(new_json);
结果
##user##
"first_name": test
"second_name": second name
##profile##
##test##
"img": img
有没有更好的方法来更改我想要的东西(自定义的)的大括号?
- 左括号 ({) 必须是 ##KEY_NAME##
- 括号 (}) 必须是 ##/KEYNAME##
期望的结果
##user##
"first_name": test
"second_name": second name
##profile##
##test##
"img": img
##/test##
##/profile##
##/user##
##company##
"name": company 1
##company_nested##
"test": test
##/company_nested##
##/company##
您可以遍历对象的条目。如果 values 是一个对象,则递归调用函数并将对象包装在 ##${k}##
和 ##/${k}##
const input={user:{first_name:"test",second_name:"second name",profile:{test:{img:"img"}}},company:{name:"company 1",company_nested:{test:"test"}}};
function replace(o) {
return Object.entries(o).map(([k, v]) => {
if (typeof v === 'object')
return `##${k}##
${replace(v)}
##/${k}##`
else
return `"${k}": ${v}`
}).join("\n")
}
console.log(replace(input))
如果多行模板文字难以阅读,您可以创建一个数组并使用 join
:
const replace = o =>
Object.entries(o).map(([k, v]) =>
typeof v === 'object'
? [`##${k}##`, replace(v), `##/${k}##`].join('\n')
: `"${k}": ${v}`
).join("\n")
我假设您的 json 格式正确。如果没有,您可能需要在代码中处理。
第 1 步:将您的 json 转换为字符串。
let str = JSON.stringify(json);
第 2 步:创建一个符号映射,将现有符号作为键,将新符号作为值。
let symbolMap = new Map();
symbolMap.set("{", "$");
symbolMap.set("}", "%");
迭代字符串中的每个字符,检查字符是否存在于映射中,如果存在,则替换新值。
for (let i = 0; i < str.length; i++) {
if (symbolMap.get(str[i])) {
str = str.replace(str[i], symbolMap.get(str[i]));
}
}
打印输出
console.log(str);
输出: 之前:
{"user":{"first_name":"test","second_name":"second name","profile":{"test":{"img":"img"}}},"company":{"name":"company 1","company_nested":{"test":"test"}}}
之后:
$"user":$"first_name":"test","second_name":"second name","profile":$"test":$"img":"img"%%%,"company":$"name":"company 1","company_nested":$"test":"test"%%%
完整代码:
let json = {
user: {
first_name: "test",
second_name: "second name",
profile: {
test: {
img: "img",
},
},
},
company: {
name: "company 1",
company_nested: {
test: "test",
},
},
};
let str = JSON.stringify(json);
let symbolMap = new Map();
symbolMap.set("{", "$");
symbolMap.set("}", "%");
console.log(str);
for (let i = 0; i < str.length; i++) {
if (symbolMap.get(str[i])) {
str = str.replace(str[i], symbolMap.get(str[i]));
}
}
console.log(str);
此方法基于单个递归调用的 reduce
r 函数。它也是一个通用的标记生成解决方案,因为它可以通过 reducer 函数的第一个参数进行配置 ...
function createCustomMarkupRecursively(collector, [key, value], idx) {
collector.config = collector.config || {};
collector.level = collector.level || 0;
const {
markup = '',
config: {
quote = '"',
prefix = '##', suffix = '##',
terminator = '/', separator = '\n',
},
} = collector;
const markupBlockSeparator = ((collector.level === 0) && (idx > 0))
? separator
: '';
if (value && (typeof value === 'object')) {
++collector.level;
collector.markup = [
markup,
markupBlockSeparator,
`${ prefix }${ key }${ suffix }\n`,
Object.entries(value).reduce(
createCustomMarkupRecursively,
Object.assign(collector, { markup: ''}),
).markup,
`${ prefix }${ terminator }${ key }${ suffix }\n`,
].join('');
--collector.level;
} else {
collector.markup = [
markup,
markupBlockSeparator,
quote,
key,
quote,
`: ${ value }\n`,
].join('');
}
return collector;
}
const data = {
user: {
first_name: "test",
second_name: "second name",
profile: {
test: {
img: "img",
},
},
},
company: {
name: "company 1",
company_nested: {
test : "test",
},
},
};
const { markup } = Object
.entries(data)
.reduce(createCustomMarkupRecursively, {/*
config: {
quote: '"',
prefix: '##',
suffix: '##',
terminator: '/',
separator: '\n'
},*/
markup: '',
});
// according to the OP ...
console.log(markup);
// customization sample ...
console.log(
Object
.entries(data)
.reduce(createCustomMarkupRecursively, {
config: {
quote: "'",
prefix: '<',
suffix: '>',
terminator: '$',
separator: '\n<-- // -->\n\n',
},
markup: '## another markup configuration result ##\n\n',
}).markup
)
.as-console-wrapper { min-height: 100%!important; top: 0; }