我有以下示例查询,它们表示不同复杂程度的对象:
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"
}
]
要做到这一点,我认为它必须逐个字符地抓取字符串,计算它当前正在查看的内容并构建/遍历对象。也许有一些我可以使用的递归正则表达式?
有关如何做到最好的想法吗?任何想法,概念等都将受到极大的赞赏。
答案 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错误,仍有无效的查询要处理,但认为这是一个好的开始。 我不知道递归正则表达式,但编写这样一个函数的时间并不长。