如何在JavaScript中将字符串树解析为数组

时间:2014-09-24 20:57:47

标签: 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)); " +
         "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(')'));
    });
}

..但那是错误的。随意调用任何功能工具包(underscore.js等)。不,这不是家庭作业,而是我写的一本书。谢谢你的帮助!

2 个答案:

答案 0 :(得分:4)

您可以像这样使用Array.prototype.reduce()

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; // keep count of opened brackets

var result = Array.prototype.reduce.call(str, function(prev, curr) {
  if (curr === '(' && cnt++ === 0) prev.push('');
  if (cnt > 0) prev[prev.length-1] += curr;
  if (curr === ')') cnt--;
  return prev;
}, []);

console.log(result);

JSFiddle mirror

答案 1 :(得分:1)

你可能应该使用解析器,但这是一个快速而肮脏的解决方案,有点像迷你解析器:

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);

jsFiddle

正则表达式将标记分为三类,堆栈开启,堆栈关闭或中性。如果它找到堆栈启动器并且堆栈上没有任何东西它会添加一个新的数组项,如果它找到更接近它会使堆栈减少一个。在堆栈为零之前,它将继续附加到当前数组项。

我无法帮助它,所以我继续完成简单的解析器,以便将字符串输出为树,其中根属性是键(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;
}

jsFiddle

Regular Expression