我有一个数据对象,需要一个简单的 js 方法将该对象解析为 quill 支持的格式文本编辑器(用链接替换占位符)。
我有:
const data = {
text: 'Hello this is $link1$ and here is $link2$ and now finally $link3$ cool.',
links: {
$link3$: ['link 3', 'https://www.link3.com'],
$link1$: ['link 1', 'https://www.link1.com'],
$link2$: ['link 2', 'https://www.link2.com']
}
};
需要一个简单的 javascript/typescript 函数,我将 data
对象传递给它并返回:
我需要什么:
[
{ insert: 'Hello this is ' },
{
insert: 'link 1',
attributes: { link: 'https://www.link1.com' }
},
{ insert: ' and here is' },
{
insert: 'link 2',
attributes: { link: 'https://www.link2.com' }
},
{ insert: ' and now finally' },
{
insert: 'link 3',
attributes: { link: 'https://www.link3.com' }
},
{ insert: ' cool.' },
]
最佳答案
由于这是 TypeScript,因此定义输入和输出类型的接口(interface)很有帮助。根据您的示例,我将猜测以下内容,但您显然可以更改它们以适合您的用例:
更新:显然 Data
中的 links
属性应该是可选的,因此我将更改它以反射(reflect)这一点。
interface Data {
text: string;
links?: { [k: string]: [string, string] | undefined }
}
interface ParsedData {
insert: string;
attributes?: { link: string }
}
现在我们要定义一个 parse()
函数,它接受 Data
类型的参数并生成 ParsedData[]
类型的结果>。这是一种可能的方法:
const parse = (d: Data): ParsedData[] => d.text.
split(/(\$\w+\$)/).
map(s => ({ s: s, l: d.links?.[s] })).
map(({ s, l }) => l ? { insert: l[0], attributes: { link: l[1] } } : { insert: s });
我在这里所做的是将 text
字符串拆分为由正则表达式 /(\$\w+\$)/
的匹配项分隔的 block 。该表达式指定一段文本,该文本以美元符号 $
开头,后跟“单词”字符(字母、数字和下划线),然后以另一个美元符号结束。同样,如果这与您的用例不完全匹配,您可以调整正则表达式来实现这一点。
现在我们有一个要处理的字符串数组。本质上,接下来的两行将每个字符串映射到一个对象。如果字符串是数据的 links
属性的键,它将查找该属性(d.links?.[s]
使用 s
作为 d.links
对象中的属性键;如果 d.links?.[s]
为 undefined
,则表示 s
不作为键出现。请注意,?.
表示法是 optional chaining,并考虑了 d.links
本身可能丢失的可能性)并将其格式化为 insert
/attributes
对象。否则,它只是将字符串作为 insert
属性,而没有 attributes
。
这是示例代码的输出:
console.log(JSON.stringify(parse(data)));
/* [
{"insert":"Hello this is "},
{"insert":"link 1","attributes":{"link":"https://www.link1.com"}},
{"insert":" and here is "},
{"insert":"link 2","attributes":{"link":"https://www.link2.com"}},
{"insert":" and now finally "},
{"insert":"link 3","attributes":{"link":"https://www.link3.com"}},
{"insert":" cool."}
] */
这看起来像你想要的。当然,这里存在各种潜在的边缘情况,因此您应该非常小心地明确指定当您收到“奇怪”输入时想要发生的情况。例如,该函数执行以下操作:
console.log(JSON.stringify(parse({
text: "What do you $expect$ to happen here",
links: {
" to happen here": ["oopsie", "doopsie"],
}
})))
/* [
{"insert":"What do you "},
{"insert":"$expect$"},
{"insert":"oopsie","attributes":{"link":"doopsie"}}
] */
这是“正确的”吗?谁知道。所以要小心。
<小时/>好的,希望有帮助;祝你好运!
<小时/>更新:你问如何走另一个方向。这确实是一个单独的问题,但这是我的答案:
function unparse(parsedData: ParsedData[]): Data {
function uniqueLinkKey(links: { [k: string]: any }, displayString: string): string {
const k = displayString.replace(/\W/g, "");
let i: "" | number;
for (i = ""; "$" + k + i + "$" in links; i = +i + 1) { }
return "$" + k + String(i) + "$";
}
const ret: Required<Data> = { text: "", links: {} };
for (let d of parsedData) {
if (d.attributes) {
const key = uniqueLinkKey(ret.links, d.insert);
ret.text += key;
ret.links[key] = [d.insert, d.attributes.link];
} else {
ret.text += d.insert;
}
}
return ret;
}
当输入前一个函数的输出时,会产生以下结果:
console.log(JSON.stringify(unparse(parsedData)));
/* { "text":"Hello this is $link1$ and here is $link2$ and now finally $link3$ cool.",
"links":{
"$link1$":["link 1","https://www.link1.com"],
"$link2$":["link 2","https://www.link2.com"],
"$link3$":["link 3","https://www.link3.com"]
}} */
上面的实现更多的是命令式风格,因为纯功能方法可能过于密集。唯一“有趣”的事情是,如果链接键具有相同的显示文本,您可能永远不想覆盖它们,因此 uniqueLinkKey()
函数确保它生成一个新的正在构建的 links
对象中尚不存在链接键:
console.log(JSON.stringify(unparse([
{ insert: "Repeats are bad: " },
{ insert: "ECHO", attributes: { link: "https://one.example.com" } },
{ insert: " and " },
{ insert: "ECHO", attributes: { link: "https://two.example.com" } },
{ insert: " and " },
{ insert: "ECHO", attributes: { link: "https://three.example.com" } },
{ insert: "!" },
])));
/* {"text":"Repeats are bad: $ECHO$ and $ECHO1$ and $ECHO2$!",
"links":{
"$ECHO$":["ECHO","https://one.example.com"],
"$ECHO1$":["ECHO","https://two.example.com"],
"$ECHO2$":["ECHO","https://three.example.com"]
}} */
所有三个链接都有显示文本 "ECHO"
,但该函数会生成三个不同的键:"$ECHO$"
、"$ECHO1 $"
和 "$ECHO2$"
。
现在,可能存在各种边缘情况,您应该考虑它们。但我几乎可以肯定已经完成了。祝你好运!
关于javascript - 如何将Javascript对象解析为对象数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60491367/