我喜欢经常采用的一般解析方法如下:
- 逐个字符循环遍历整个文本块。
- 如果你发现一个字符表示一个单元的开始,调用一个专门的子函数来解析下一个字符。
- 在每个子函数中,如果您发现某些字符,则调用其他子函数
- 当找到一个字符时从每个子函数返回,这表明该单元已经结束。
这是一个小例子:
var text = "@func(arg1,arg2)"
function parse(text) {
var i, max_i, ch, funcRes;
for (i = 0, max_i = text.length; i < max_i; i++) {
ch = text.charAt(i);
if (ch === "@") {
funcRes = parseFunction(text, i + 1);
i = funcRes.index;
}
}
console.log(funcRes);
}
function parseFunction(text, i) {
var max_i, ch, name, argsRes;
name = [];
for (max_i = text.length; i < max_i; i++) {
ch = text.charAt(i);
if (ch === "(") {
argsRes = parseArguments(text, i + 1);
return {
name: name.join(""),
args: argsRes.arr,
index: argsRes.index
};
}
name.push(ch);
}
}
function parseArguments(text, i) {
var max_i, ch, args, arg;
arg = [];
args = [];
for (max_i = text.length; i < max_i; i++) {
ch = text.charAt(i);
if (ch === ",") {
args.push(arg.join(""));
arg = [];
continue;
} else if (ch === ")") {
args.push(arg.join(""));
return {
arr: args,
index: i
};
}
arg.push(ch);
}
}
小提琴
这个例子只是解析函数表达式,它遵循语法“@functionName(argumentName1, argumentName2, ...)”。一般的想法是只访问每个字符一次,而无需保存当前状态,如“hasSeenAtCharacter”或“hasSeenOpeningParentheses”,当您解析大型结构时,它们会变得非常混乱。
请注意,这是一个非常简化的示例,它遗漏了所有错误处理和类似的东西,但我希望可以看到总体思路。另请注意,我并不是说您应该一直使用这种方法。这是一种非常通用的方法,可以在许多场景中使用。但这并不意味着它不能与正则表达式结合使用,例如,如果它在文本的某些部分比解析每个单独的字符更有意义。
最后一点:如果你把专门的解析函数放在主解析函数中,你可以省去麻烦,这样所有函数都可以访问同一个变量i
。