科目表转树形结构:代码错误排查及正确实现方案
会计科目表树形结构构建问题排查与修复
问题说明
我有一段表示会计科目表的字符串,期望将其转换为指定的层级树形结构,但自行编写的createChartOfAccountsTree函数无法正确构建父子关系,需要排查代码错误并提供正确实现方案。
原始科目表字符串
1: Comptes de capitaux 10. Capital et Réserves. 101. Capital. 1011. Capital souscrit - non appelé. 1012. Capital souscrit - appelé, non versé. 1013. Capital souscrit - appelé, versé. 10131. Capital non amorti. 10132. Capital amorti. 1018. Capital souscrit soumis à une réglementation particulière. 105. Ecarts de réévaluation. 108. Compte de l'exploitant.
期望输出结构
{ "1": { id: "1", accountName: "Comptes de capitaux", children: { "10": { id: "10", accountName: "Capital et Réserves", children: { "101": { id: "101", accountName: "Capital", children: { "1011": { id: "1011", accountName: "Capital souscrit - non appelé", children: {} }, "1012": { id: "1012", accountName: "Capital souscrit - appelé, non versé", children: {} }, "1013": { id: "1013", accountName: "Capital souscrit - appelé, versé", children: { "10131": { id: "10131", accountName: "Capital non amorti", children: {} }, "10132": { id: "10132", accountName: "Capital amorti", children: {} } } }, "1018": { id: "1018", accountName: "Capital souscrit soumis à une réglementation particulière", children: {} } } }, "105": { id: "105", accountName: "Ecarts de réévaluation", children: {} }, "108": { id: "108", accountName: "Compte de l'exploitant", children: {} } } } } } }
错误代码问题排查
原函数存在以下几个关键错误:
- ID提取错误:直接用空格分割行,会把带标点的内容(如
1:、10.)当成ID,导致后续父ID计算完全错误。 - 字符串替换语法错误:
accountName.replace(".","",)多了一个多余的逗号,属于语法错误,会导致函数执行失败。 - 名称清理不彻底:仅替换第一个
.,无法清除科目名称末尾的.,也没处理名称前后的多余空格。 - 父节点判断逻辑脆弱:依赖
accounts对象直接查找父ID,但如果ID提取错误,父ID必然不存在,导致所有节点都被当成顶级节点。
正确实现方案
以下是修复后的函数,通过正则匹配准确提取ID和名称,正确构建父子层级:
function createChartOfAccountsTree(input) { const accounts = {}; // 按行分割,过滤空行并去除每行前后空格 const lines = input.split("\n").map(line => line.trim()).filter(line => line); lines.forEach(line => { // 用正则匹配ID(开头的数字)、分隔符(:或.)、科目名称 const match = line.match(/^(\d+)[.:]\s*(.*?)\.?\s*$/); if (!match) return; const id = match[1]; const accountName = match[2].trim(); const account = { id, accountName, children: {} }; // 存入全局索引 accounts[id] = account; // 计算父ID:长度大于1时取前length-1位 if (id.length > 1) { const parentId = id.slice(0, -1); const parent = accounts[parentId]; if (parent) { parent.children[id] = account; } } }); // 返回顶级节点(ID长度为1的节点) return Object.values(accounts).filter(item => item.id.length === 1).reduce((acc, item) => { acc[item.id] = item; return acc; }, {}); } // 测试调用 const input = `1: Comptes de capitaux 10. Capital et Réserves. 101. Capital. 1011. Capital souscrit - non appelé. 1012. Capital souscrit - appelé, non versé. 1013. Capital souscrit - appelé, versé. 10131. Capital non amorti. 10132. Capital amorti. 1018. Capital souscrit soumis à une réglementation particulière. 105. Ecarts de réévaluation. 108. Compte de l'exploitant.`; console.log(createChartOfAccountsTree(input));
关键优化点
- 正则匹配提取:通过
/^(\d+)[.:]\s*(.*?)\.?\s*$/准确分隔ID和科目名称,自动处理:和.两种分隔符,同时清除名称末尾的.和多余空格。 - 全局节点索引:先将所有节点存入
accounts对象,确保父节点查找时一定存在(因为输入是按层级从高到低排列)。 - 层级关联逻辑:通过ID长度计算父ID,将当前节点挂载到父节点的
children对象中。 - 返回顶级节点:最终只返回ID长度为1的顶级节点,符合树形结构的根节点要求。
内容的提问来源于stack exchange,提问作者salmen ben ali
相关产品推荐
相关产品推荐

