本帖最后由 pansong291 于 2022-11-11 23:37 编辑
<!DOCTYPE html>
<html lang="zh-cmn-Hans">
<head>
<meta charset="UTF-8" />
<title>Data Convertor</title>
</head>
<body></body>
<script>
// 原数据是这样的(即下标0为键,下标1为值)
const arr = [
['标题', '这是标题'],
['副标题', '这是副标题'],
['文字颜色', 'white'],
['背景颜色', 'red']
]
// 要输出成这样
// const objConfig = {
// title: {
// text: "这是标题",
// subtext: "这是副标题"
// },
// color: {
// textColor: 'white',
// bgColor: 'red'
// }
// }
// 注意,源数据行的顺序可能会有变化,所以,我考虑可能需要一个枚举来建立关系对应
const arrConfigList = [
{ name: '标题', target: 'title.text' },
{ name: '副标题', target: 'title.subtext' },
{ name: '文字颜色', target: 'color.textColor' },
{ name: '背景颜色', target: 'color.bgColor' }
]
// 到这里就没有什么思路了...
const data = convert(arr, arrConfigList)
console.log(data)
const pre = document.createElement('pre')
pre.innerText = JSON.stringify(data, null, 2)
document.body.append(pre)
function convert(arr, configList) {
const mapping = {}
for (let map of configList) {
mapping[map.name] = `.${map.target}`
}
const result = {}
for (let item of arr) {
if (item && item.length && item.length > 1) {
const path = mapping[item[0]]
if (path) parsePathOf(result, path, item[1])
}
}
return result
}
/**
* 根据指定的字符串解析对应路径并将指定数据填充到指定对象中。
* 指定的字符串格式不正确将会抛出异常。
*
* @param root 需要填充数据的对象或数组
* @param pathStr 指定路径的字符串,必须以点号或方括号开头,如 .person.name 或 [0].name
* @param value 需要填充的数据
*/
function parsePathOf(root, pathStr, value) {
let errMsg = 'error: illegal path string: ' + pathStr
let cur = root
let path = pathStr
let reg = /[\[.]/
while (true) {
// 检查当前对象是否有值且是否是对象或数组类型
if (!cur || !(cur instanceof Object)) {
let deepPath = pathStr.substring(0, pathStr.lastIndexOf(path))
throw 'error: the value of "<root>' + deepPath + '" is not a(n) object/array'
}
// 先查找一次
let matchArr = path.match(reg)
// 未找到或者不在首个位置抛异常
if (!matchArr || matchArr.index !== 0) {
throw errMsg
}
// 去掉第一个符号
path = path.substring(1)
// 继续找下一个
let nextMatch = path.match(reg)
// 获取当前属性名和下个符号
let field
let symbol
if (nextMatch) {
field = path.substring(0, nextMatch.index)
symbol = nextMatch[0]
} else {
field = path
symbol = undefined
}
if (matchArr[0] === '[') {
// 检查一下中括号是否配对
if (field.charAt(field.length - 1) !== ']') {
throw errMsg
}
// 把属性名最后的 ] 去掉,顺便去掉引号
field = removeQuote(field.substring(0, field.length - 1))
}
// 检查属性名不为空,且不能包含右方括号
if (!field || field.indexOf(']') >= 0) {
throw errMsg
}
if (symbol === '.') {
// 点号表示是对象,需要保证当前路径是对象
if (cur[field] === undefined || cur[field] === null) {
cur[field] = {}
}
} else if (symbol === '[') {
// 中括号表示是数组,需要保证当前路径是数组
if (cur[field] === undefined || cur[field] === null) {
cur[field] = []
}
} else {
// 未找到下个,结束
cur[field] = value
break
}
// 进入下一次迭代
cur = cur[field]
path = path.substring(nextMatch.index)
}
}
/**
* 如果字符串的首尾都是引号,则去除首尾的引号。检测的引号有单引号、双引号和反引号。
*
* @param str 受检字符串
* @returns {string} 去除首尾引号的字符串或它本身
*/
function removeQuote(str) {
let reg = /^(["'`]).*\1$/
if (reg.test(str)) {
str = str.substring(1, str.length - 1)
}
return str
}
</script>
</html>
|