如何在JavaScript中将字符串树解析为数组
假设我得到一个API响应,它返回一个树状结构,如下所示:如何在JavaScript中将字符串树解析为数组,javascript,functional-programming,underscore.js,graph-theory,Javascript,Functional Programming,Underscore.js,Graph Theory,假设我得到一个API响应,它返回一个树状结构,如下所示: "gw43g: (-95.147, 38.5818); " + "jp987h: (" + "bvp7: (-97.450, 30.150); " + "7g8oi: (" + "34ilht: (-82.192997, 29.39719); " + "34hb1: (-122.25, 37.47)); " + "b2
"gw43g: (-95.147, 38.5818); " +
"jp987h: (" +
"bvp7: (-97.450, 30.150); " +
"7g8oi: (" +
"34ilht: (-82.192997, 29.39719); " +
"34hb1: (-122.25, 37.47)); " +
"b238: (-71.0349, 42.2129)); " +
"ao8yh: (-90.147, 42.5818);"
这是一根绳子
使用JavaScript,我需要将其转换为如下数组
["(-95.147, 38.5818)",
"(bvp7: (-97.450, 30.150); 7g8oi: (...)...)",
"(-90.147, 42.5818)"]
…这样,每对括号的内部都是一个数组项,而不管最外层的一对中包含多少嵌套括号
我运气不好,所以我请求你的人帮忙。这是我试过的
function getCoords(str) {
return str.split(';').map(function(s) {
return s.substring(s.indexOf('(')+1, s.lastIndexOf(')'));
});
}
但这是错误的。可以随意调用任何功能工具包(下划线.js等)。不,这不是家庭作业,这是我正在写的一本书。谢谢你的帮助 您可能应该为此使用解析器,但这里有一个类似于小型解析器的快速而肮脏的解决方案:
var src = "gw43g: (-95.147, 38.5818) .... ";
var re = /(\w+:\s*\()|(\);?)|((?:(?!\w+:\s*\(|\);?).)+)/g;
var output = [];
var match;
var stackCount = 0;
while ((match = re.exec(src)))
{
if (match[1]) {
if (stackCount == 0) output.push('');
stackCount++;
}
else if (match[2]) {
stackCount--;
}
output[output.length-1] += match[0];
}
console.log(output);
正则表达式将标记分为三类:堆栈开启器、堆栈关闭器或中性。如果它找到一个堆栈起始点,而堆栈上没有任何内容,则会添加一个新的数组项,如果它找到一个更接近的数组项,则会将堆栈向下移动一个。在堆栈为零之前,它将一直追加到当前数组项
我没办法,所以我继续做了,刚刚完成了这个简单的解析器,所以字符串被输出为一个树,其中根属性是键(gw43g),每个都有一个X,Y值,或者它是树上的一个分支
function parseBody(str) {
// rey: http://rey.gimenez.biz/s/fxd02f
var re = /\s+|(\w+)\s*:\s*\(|(\);?)|(([\-+]?\s*(?:\d*\.\d*|\d+))\s*,\s*([\-+]?\s*(?:\d*\.\d*|\d+)))/g;
var output = [];
var match;
var newObj;
var root = { children: { } }
var branch = root;
while ((match = re.exec(str)))
{
// key and open
if (match[1]) {
newObj = { parent: branch, children: { } };
branch.children[match[1]] = newObj;
// new stack
branch = newObj;
}
//
else if (match[2]) {
// move up stack
branch = branch.parent;
}
else if (match[3]) {
branch.X = parseFloat(match[4]);
branch.Y = parseFloat(match[5]);
}
}
return root;
}
您可能应该为此使用解析器,但这里有一个类似于小型解析器的快速而肮脏的解决方案:
var src = "gw43g: (-95.147, 38.5818) .... ";
var re = /(\w+:\s*\()|(\);?)|((?:(?!\w+:\s*\(|\);?).)+)/g;
var output = [];
var match;
var stackCount = 0;
while ((match = re.exec(src)))
{
if (match[1]) {
if (stackCount == 0) output.push('');
stackCount++;
}
else if (match[2]) {
stackCount--;
}
output[output.length-1] += match[0];
}
console.log(output);
正则表达式将标记分为三类:堆栈开启器、堆栈关闭器或中性。如果它找到一个堆栈起始点,而堆栈上没有任何内容,则会添加一个新的数组项,如果它找到一个更接近的数组项,则会将堆栈向下移动一个。在堆栈为零之前,它将一直追加到当前数组项
我没办法,所以我继续做了,刚刚完成了这个简单的解析器,所以字符串被输出为一个树,其中根属性是键(gw43g),每个都有一个X,Y值,或者它是树上的一个分支
function parseBody(str) {
// rey: http://rey.gimenez.biz/s/fxd02f
var re = /\s+|(\w+)\s*:\s*\(|(\);?)|(([\-+]?\s*(?:\d*\.\d*|\d+))\s*,\s*([\-+]?\s*(?:\d*\.\d*|\d+)))/g;
var output = [];
var match;
var newObj;
var root = { children: { } }
var branch = root;
while ((match = re.exec(str)))
{
// key and open
if (match[1]) {
newObj = { parent: branch, children: { } };
branch.children[match[1]] = newObj;
// new stack
branch = newObj;
}
//
else if (match[2]) {
// move up stack
branch = branch.parent;
}
else if (match[3]) {
branch.X = parseFloat(match[4]);
branch.Y = parseFloat(match[5]);
}
}
return root;
}
您可以这样使用:
"gw43g: (-95.147, 38.5818); " +
"jp987h: (" +
"bvp7: (-97.450, 30.150); " +
"7g8oi: (" +
"34ilht: (-82.192997, 29.39719); " +
"34hb1: (-122.25, 37.47)); " +
"b238: (-71.0349, 42.2129)); " +
"ao8yh: (-90.147, 42.5818);"
var str=“gw43g:(-95.147,38.5818)+
“jp987h:(”+
bvp7:(-97.450,30.150)+
“7g8oi:(”+
34ilht:(-82.192997,29.39719)+
34hb1:(-122.25,37.47))+
b238:(-71.0349,42.2129))+
ao8yh:(-90.147,42.5818)
var cnt=0;//记下打开的括号
var result=Array.prototype.reduce.call(str,function(prev,curr){
如果(curr==='('&&cnt++===0)上推('');
如果(cnt>0)上一个[上一个长度-1]+=curr;
如果(curr==''))cnt--;
返回上一个;
}, []);
控制台日志(结果)代码>您可以这样使用:
"gw43g: (-95.147, 38.5818); " +
"jp987h: (" +
"bvp7: (-97.450, 30.150); " +
"7g8oi: (" +
"34ilht: (-82.192997, 29.39719); " +
"34hb1: (-122.25, 37.47)); " +
"b238: (-71.0349, 42.2129)); " +
"ao8yh: (-90.147, 42.5818);"
var str=“gw43g:(-95.147,38.5818)+
“jp987h:(”+
bvp7:(-97.450,30.150)+
“7g8oi:(”+
34ilht:(-82.192997,29.39719)+
34hb1:(-122.25,37.47))+
b238:(-71.0349,42.2129))+
ao8yh:(-90.147,42.5818)
var cnt=0;//记下打开的括号
var result=Array.prototype.reduce.call(str,function(prev,curr){
如果(curr==='('&&cnt++===0)上推('');
如果(cnt>0)上一个[上一个长度-1]+=curr;
如果(curr==''))cnt--;
返回上一个;
}, []);
控制台日志(结果)
我做对了:您正在对字符串使用Array.prototype.reduce
函数,以便它像字符数组一样逐个字符枚举?非常酷。@DanielGimenez:没错!大多数数组方法也适用于“类似数组”的对象,如字符串。看一看:并且看起来像var result=str.split(“”)。reduce((prev,curr)=>{…})也可以工作吗?或者,您可以调用:Array.from(str)。reduce((prev,curr)=>/*code*/,[])
我很正确:您正在对字符串使用Array.prototype.reduce
函数,这样它就可以像一个字符数组一样一个字符一个字符地枚举?非常酷。@DanielGimenez:没错!大多数数组方法也适用于“类似数组”的对象,如字符串。看一看:而且似乎var result=str.split(“”)。reduce((prev,curr)=>{…})也可以工作吗?或者,您可以调用:Array.from(str)。reduce((prev,curr)=>/*code*/,[])
我非常喜欢stewe的答案,它简洁地解决了您描述的问题,但是我继续,在我的答案中添加了一个完全实现的解析器,这样您就可以将数据作为对象而不是字符串数组来获取。[我真的只是想进入你的书:-)丹尼尔,你的答案更长,我希望能有更多的“函数式编程”,但是它快了5倍!我使用JSLitmus进行测试,结果如下:…我希望我能选择两者作为正确答案我真的很喜欢stewe的答案,它简洁地解决了您描述的问题,但我继续在我的答案中添加了一个完全实现的解析器,以便您可以将数据作为对象而不是字符串数组获取。[我真的只是想进入你的书:-)丹尼尔,你的答案更长,我希望能有更多的“函数式编程”,但是它快了5倍!我使用JSLitmus进行测试,结果如下:……我希望我能选择两者作为正确答案