将字符串解析为对象(自定义格式)

时间:2015-07-22 13:05:49

标签: javascript

我有以下示例查询,它们表示不同复杂程度的对象:

abc,def,ghi

abc,\def,ghi

abc,\def{ghi,jkl},mno

abc,\def{ghi,\jkl},mno

abc,\def{ghi,\jkl{mno,pqr,\stu},vwx

在上面的例子中,我刚用了3个字母表示一个单词。这个词可以是任何长度。

有两种不同类型的单词。如果一个单词以反斜杠开头,则称为边。如果不是,则称为字段。

字段和边可以属于边。这些是在边{}内定义的。这是无限递归的,因此单词可以属于属于边缘的边缘等。

我想解析此字符串以将其转换为JavaScript对象。

很难解释,所以一个例子可能更好......

例如1,这应该转换为:

[
    {
        type: "field",
        val: "abc"
    },
    {
        type: "field",
        val: "def"
    },
    {
        type: "field",
        val: "ghi"
    },
]

例如2,这应该转换为:

[
    {
        type: "field",
        val: "abc"
    },
    {
        type: "edge",
        val: "def",
        children: []
    },
    {
        type: "field",
        val: "ghi"
    }
]

例如,这应该转换为:

[
    {
        type: "field",
        val: "abc"
    },
    {
        type: "edge",
        val: "def",
        children: [
            {
                type: "field",
                val: "ghi"
            },
            {
                type: "edge",
                val: "jkl",
                children: [
                    {
                        type: "field",
                        val: "mno"
                    },
                    {
                        type: "field",
                        val: "pqr"
                    },
                    {
                        type: "edge",
                        val: "stu",
                        children: []
                    }
                ]
            }
        ]
    },
    {
        type: "field",
        val: "vwx"
    }
]

要做到这一点,我认为它必须逐个字符地抓取字符串,计算它当前正在查看的内容并构建/遍历对象。也许有一些我可以使用的递归正则表达式?

有关如何做到最好的想法吗?任何想法,概念等都将受到极大的赞赏。

3 个答案:

答案 0 :(得分:1)

这是一个递归函数。唯一真正的问题是,这不适用于高代码点字符。

function parse (string) {
    var array = []
      , children = ''
      , recursive = false
      , level = 0
      , object = { type: 'field', val: ''}
    for (var i = 0; i < string.length; i++) {
        var ch = string.charAt(i)
        if (recursive) {
            if (ch === '}' && level === 0) {
                object.children = parse(children)
                array.push(object)
                object = {type: 'field', val: ''}
                recursive = false
                continue
            }else if (ch === '}') {
                level--
                children += ch 
            } else if (ch === '{') {
                level++
                children += ch 
            } else {
                children += ch
                continue
            }
        }

        if (ch === ',' && object.val.length > 0) {
            if (object.type == 'edge') {
                object.children = []
                array.push(object)
                object = {type: 'field', val: ''}
            } else {
                array.push(object)
                object = {type: 'field', val: ''}
            }
        } else if (ch === '{') {
            recursive = true
            continue
        } else if (ch === '\u005C') {
            object.type = 'edge'
        } else {
            object.val += ch
        }
    }

    if (object.val.length > 0) {
        array.push(object)
    }
    return array
}

答案 1 :(得分:1)

我建议写一个语法并实现一个recursive descent parser。他们非常简单。

var parse = function(s){

    var i = 0;

    var peek = function(c){
        return s[i] === c;
    };

    var next = function(c){
        var found = s[i];
        if(c && s[i] !== c){
            throw 'expected ' + c + ' at char ' + i + ': ' + s.slice(i,20);
        }
        i += 1;
        return found;
    };

    var word = function(){
        var w = '';
        if(!/[a-z]/.test(s[i])){
            throw 'expected a word at char ' + i + ': ' + s.slice(i,20);
        }
        while(s[i] && /[a-z]/.test(s[i])){
            w += s[i];
            i += 1;
        }
        return w;
    };

    var edge = function(){
        next('\\');
        var val = word();
        var e = {
            type: 'edge',
            val: val
        };
        if(peek('{')){
            next('{');
            e.children = fields_or_edges();
            next('}');
        }
        return e;
    };

    var field = function(){
        return {
            type: 'field',
            val: word()
        };
    };

    var fields_or_edges = function(){
        var stuff = [];
        var thing;
        do {
            if(peek('\\')){
                thing = edge();
            }else{
                thing = field();
            }
            stuff.push(thing);
        }while(peek(',') && next());
        return stuff;
    };

    return fields_or_edges();
};

让我们测试一下。

[
    'abc,def,ghi',
    'abc,\\def,ghi',
    'abc,\\def{ghi,jkl},mno',
    'abc,\\def{ghi,\\jkl},mno',
    'abc,\\def{ghi,\\jkl{mno,pqr,\\stu},vwx' // uncaught exception: expected } at char 35: 
].forEach(function(s){
    console.log(JSON.stringify(parse(s), null, 4));
});

请注意,如果您运行此操作,解析器会在最终测试字符串中的char 35处选择一个错误:no closing&#39;}&#39;。

答案 2 :(得分:0)

如果没有正则表达式,我将如何做到这一点:

function parseArray(s) {
    var w = "", i = 0, c, array = [];
    for (i = 0; i < s.length; i++) {
        c = s.atChar(i);
        if (c == ",") {
            array.push(parseObject(w));
        } else {
            w += c;
        }

    }
}

function parseObject(s) {
    if (s.length === 0) {
        return null;
    }

    if (s.atChar(0) !== "\\") {
        return {
            type: "field",
            value: w
        };
    }
    var v, a, c, status = 0;
    for (var i = 1; i < s.length; i++) {
        c = s.atChar(i);
        if (status === 0) {
            if (c === "{") {
                status = 1;
            } else {
                v += c;
            }
        } else {
            if (c === "}") {
                break;
            }
            a += c;
        }
    }

    return {
        type: "edge",
        value: v,
        children: parseArray(a)
    };

}

可能存在一些javascript错误,仍有无效的查询要处理,但认为这是一个好的开始。 我不知道递归正则表达式,但编写这样一个函数的时间并不长。