问题
I have text in the format
var text = "{{A-B-C}{A-C-B}D-B}{E}F" //example 1
The text can be something else like:
var text = "{{{A-B-C}{C-A-B}D-E}{B-C}E-A}{F}G" //example 2
So the node structure can change but the delimiting of - and {} remains the same to indicate heirarchy.
I would like to create a tree out of this either as a javascript object or JSON for d3js tree layout. I can use lodash/jquery or any other library I wish.
The eventual layout I need is like this image, for the var text example 1 above
How can I convert the string to nested data in the format like below (for var text
example 1). I have been struggling to find a way to do it. Any help or direction is appreciated.
var textobject = {
name: "F",
children: [{
name: "E",
children: []
},
{
name: "B",
children: [{
name: "D",
children: [{
name: "B",
children: [{
name: "C",
children: [{
name: "A",
children: []
}, ]
}, ]
}, {
name: "C",
children: [{
name: "B",
children: [{
name: "A",
children: []
}, ]
}, ]
}, ]
}, ]
},
]
}
回答1:
You can solve this by using arrays as stacks. There's a proper explanation from the comments of the code below.
function parseTree(string) {
// split string into an array
// reduce the array into a proper tree where the
// first and last item will be the entire tree, hence,
// the access of the first index from the last part
// of this expression
return string.split(/(}|{|\-)/)
.reduce(parseTreeReducer, [])[0];
}
function parseTreeReducer(array, ch, index, original) {
// always track the index of the open bracket
// from the array stack
let indexBracket = array.lastIndexOf('{');
if(ch === '{') { // is it an open bracket?
// store it in the array stack!
array.push(ch);
} else if(ch === '}') { // is it a close bracket?
// remove the last open bracket
// this prepares the nodes after the open bracket index
// to be the children of the next node
array.splice(indexBracket, 1);
} else if(ch !== '-' && ch) { // make sure to ignore '-' key
// push the node in the array stack
array.push({
name: ch, // name
// ensure that we only get the nodes that are after the
// last open bracket from the array stack and remove them.
// These removed nodes will be assigned as children for
// this current node
children: array.splice(
// make sure we don't delete the open bracket
indexBracket + 1,
// only remove items beyond the open bracket index
array.length - indexBracket - 1
).reverse() // reverse to represent the expected output (optional!)
});
}
// return the array stack
return array;
}
function parseTree(string) {
// split string into an array
// reduce the array into a proper tree where the
// first and last item will be the entire tree, hence,
// the access of the first index from the last part
// of this expression
return string.split(/(}|{|\-)/)
.reduce(parseTreeReducer, [])[0];
}
function parseTreeReducer(array, ch, index, original) {
// always track the index of the open bracket
// from the array stack
let indexBracket = array.lastIndexOf('{');
if(ch === '{') { // is it an open bracket?
// store it in the array stack!
array.push(ch);
} else if(ch === '}') { // is it a close bracket?
// remove the last open bracket
// this prepares the nodes after the open bracket index
// to be the children of the next node
array.splice(indexBracket, 1);
} else if(ch !== '-' && ch) { // make sure to ignore '-' key
// push the node in the array stack
array.push({
name: ch, // name
// ensure that we only get the nodes that are after the
// last open bracket from the array stack and remove them.
// These removed nodes will be assigned as children for
// this current node
children: array.splice(
// make sure we don't delete the open bracket
indexBracket + 1,
// only remove items beyond the open bracket index
array.length - indexBracket - 1
).reverse() // reverse to represent the expected output (optional!)
});
}
// return the array stack
return array;
}
/* THE CODE BELOW IS ONLY FOR DEMO USAGE */
var input = document.querySelector('input');
var output = document.querySelector('pre');
setOutput();
input.addEventListener('keyup', setOutput);
function setOutput() {
output.innerHTML = JSON.stringify(parseTree(input.value), 0, 4);
}
.as-console-wrapper{min-height:100%;top:0}
input{width: 100%}
pre{background-color: #ccc; padding: 1em}
<input type="text"
autofocus
value="{{Axe-Barathrum-Clockwork}{Abaddon-Clinkz-Bane Elemental}Dragon Knight-Bristleback}{Ezalor}Furion" />
<br>
<pre></pre>
来源:https://stackoverflow.com/questions/50673284/delimited-text-to-nested-javascript-object-json