Me gustaría poder analizar una cadena en un objeto JSON, algo como esto (el texto puede ser cualquier cosa, solo los pongo así para que pueda ver la estructura):
A AA AB ABA ABB AC ACA Ben un objeto json, estructurado así:
[ { "root": "A", "content": [ { "root": "AA", "content": [] }, { "root": "AB", "content": [ { "root": "ABA", "content": [] }, { "root": "ABB", "content": [] } ] }, { "root": "AC", "content": [ { "root": "ACA", "content": [] } ] } ] }, { "root": "B", "content": [] } ]Hasta ahora, tengo lo siguiente, pero no estoy seguro de si esta es la mejor manera de hacerlo. ¿Quizás un enfoque recursivo sería mejor?
let body = []; let indentStack = [0]; for (let line of input.split('\n')) { // input is the string I'd like to parse if (line.trim() == '') continue; // skips over empty lines let indent = line.match(/^ +/); indent = indent ? indent[0].length : 0; // matches the first group of spaces with regex, gets the indent level of this line if (indentStack[indentStack.length-1] != indent) if (indentStack.includes(indent)) indentStack.length = indentStack.indexOf(indent)+1; // remove all indent levels after it as it's returned back to a higher level else stack.push(indent); console.log(`${(indent + '[' + indentStack.join() + ']').padEnd(10, ' ')}: ${line}`); // debugging if (indentStack.length == 1) body.push({ root: line, content: [] }); else { body[body.length-1].content.push({ root: line.substring(indent), content: [] }) } } console.log(body)Lo haré de esta manera:
const data = `A AA AB ABA ABB AC ACA B`; function doTree(data) { let res = [] , levels = [ res ] ; for (let line of data.split('\n')) { let level = line.search(/\S/) >> 1 // (index of first non whitespace char) / 2 --> IF indentation is 2 spaces , root = line.trim() , content = [] ; if (!root) continue levels[level].push({root,content}) levels[++level] = content } return res } console.log( doTree(data) ) .as-console-wrapper {max-height: 100%!important;top:0 }La pregunta sobre las sangrías...
aquí puede tener pasos de sangría desiguales,
ya sea con espacios o con tabulaciones.
(no mezclar espacios y tabulaciones)
const data_023c = // indentation values are 0c, 2c, 3c `A AA AB ABA ABB AC ACA B`; const indentation= (()=> // IIFE { let indents = [] , max = -1 ; return { clear:() => { indents.length = 0 max = -1 } , get:(line, lNum='?' ) => { let ncBefore = line.search(/\S/) let level = indents.indexOf(ncBefore) if (level===-1) { if (ncBefore < max) throw `error on indentation,\n line = ${lNum},\n line value is = "${line}"` level = indents.push( ncBefore) -1 max = ncBefore } return level } } })() const doTree = data => { let res = [] , levels = [ res ] , lineN = 0 ; indentation.clear() for (let line of data.split('\n')) { lineN++ // line counter for indent error message let root = line.trim() , content = [] ; if (!root) continue let level = indentation.get(line, lineN) levels[level].push({root,content}) levels[++level] = content } return res } console.log( doTree(data_023c) ) .as-console-wrapper {max-height: 100%!important;top:0 }