Javascript解析带参数的嵌套字符串函数
我试图将此字符串解析为一组有组织的函数:Javascript解析带参数的嵌套字符串函数,javascript,regex,string,parsing,Javascript,Regex,String,Parsing,我试图将此字符串解析为一组有组织的函数: var str = "a(b, c(e, f(h,i,j), g(k,l,m(o,p,q)) ), d(r,s,t))" 理想情况下,我想把它变成这样一个对象: var obj = { func:'a', params:[ {p:'b'}, {p: { func:'c', params:[ {
var str = "a(b, c(e, f(h,i,j), g(k,l,m(o,p,q)) ), d(r,s,t))"
理想情况下,我想把它变成这样一个对象:
var obj = {
func:'a',
params:[
{p:'b'},
{p: {
func:'c',
params:[
{
p:'e',
p:{
func:'f',
params:[
{p:'h'},
{p:'i'},
{p:'j'}
]
},
p:'g',
params:[
{p:'k'},
{p:'l'},
{p:{
func:'m',
params:[
{p:'o'},
{p:'p'},
{p:'q'}
]
}}
]
}
]
}},
{
p:'d',
params:[
{p:'r'},
{p:'s'},
{p:'t'}
]
}
]
}
我尝试了大约8个小时的str.replace()str.substring()和str.indexOf()混合,但没有任何运气
任何关于如何实现我的目标的帮助都将受到欢迎
注意:函数可以采用任意数量的参数,且未设置为3
更新--我停止尝试进行字符串操作,并逐个字符地处理它。要创建所需的输出:
var str = "a(b, c(e, f(h,i,j), g(k,l,m(o,p,q)) ), d(r,s,t))";
str = str.replace('/ /g,""');
var strArr = str.split('');
var firstPass = "";
var final;
var buildObj = function(){
for(var i = 0; i < strArr.length; i++){
var letters = /^[0-9a-zA-Z]+$/;
if(strArr[i].match(letters)){
if(strArr[i + 1] == '('){
firstPass += '},{"func":' + '"' + strArr[i] + '"';
} else {
firstPass += '"' + strArr[i] + '"';
}
}
if(strArr[i] == '('){
firstPass += ',"params":[{"p":';
}
if(strArr[i] == ')'){
firstPass += '}],';
}
if(strArr[i] == ','){
firstPass += '},{"p":';
}
//console.log(job + '}')
}
var secondPass = firstPass;
secondPass += '}'
secondPass = secondPass.replace(/,{"p":}/g,'');
secondPass = secondPass.replace('},','');
secondPass = secondPass.replace(/],}/g,']}');
final = secondPass
console.log(final)
console.log(JSON.parse(final))
var str=“a(b,c(e,f(h,i,j),g(k,l,m(o,p,q))),d(r,s,t))”;
str=str.replace('//g,“”);
var strArr=str.split(“”);
var firstPass=“”;
var最终;
var buildObj=函数(){
对于(变量i=0;i
};正则表达式和字符串黑客是行不通的;正则表达式不能(直接)处理任何嵌套结构的文本(人们一直在学习这个…)。切换到单个字符并不能改善任何事情 通常,您需要的是一个生成标记(语言元素)的lexer和一个解析器(检查元素是否正确组织)
作为一个实际问题,您可以将这些内容组合成一个简单语言的连贯结构,就像OP感兴趣的语言一样。请轻松查看;按照这个答案回答如何构建树(本质上,如何构建您想要的结果结构).我看到了这个问题,并认为尝试一下可能会很有趣。我将详细介绍我的思考过程,希望能对您有所帮助 我生成的对象并不完全映射到您的对象,但可以很容易地映射到您的对象。不需要额外的工作就可以得到我生成的对象,而不会被诸如将对象放入数组之类的“无关”细节分散注意力 1.)我假设空白是无用的。第一步是用零替换所有空白
function processStatement(statement) {
return statement.replace(/[ ]/g, '');
}
// Output: a(b,c(e,f(h,i,j),g(k,l,m(o,p,q))),d(r,s,t))
2.)我的目标是创建一个树状对象,其参数不会导致更多函数成为死胡同。我需要一种解析“根”的方法,代码应该解释更多:
function produceNodeFromStatement(statement) {
var regex = new RegExp('([a-zA-Z])\\((.+)\\)', 'g');
var results = regex.exec(statement);
// This regex matches for the widest pattern: identifier(stuff-inside)
// Running the previous output would result in matching groups of:
// identifier: a
// stuff-inside: b,c(e,f(h,i,j),g(k,l,m(o,p,q))),d(r,s,t)
var root = {}
// We need a way to split the stuff-inside by commas that are not enclosed in parenthesis.
// We want to turn stuff-inside into the following array:
// [ 'b', 'c(e,f(h,i,j),g(k,l,m(o,p,q)))', 'd(r,s,t)' ]
// Since my regex-fu is bad, I wrote a function to do this, explained in the next step.
var parameters = splitStatementByExternalCommas(results[2]);
var node = {};
parameters.forEach(function (parameter) {
if (parameter.indexOf('(') == -1) {
node[parameter] = null;
} else {
// Recursion. This function produces an anonymous wrapper object around a node.
// I will need to unwrap my result.
var wrappedNode = deconstructStatement(parameter);
var key;
for (key in wrappedNode) {
node[key] = wrappedNode[key];
}
}
});
// Assign node to the node's identifier
root[results[1]] = node;
return root;
}
3.)公式中唯一缺少的部分是只使用外部逗号分割字符串的函数-因为我无法理解正则表达式,下面是splitStatementByExternalCommas
function splitStatementByExternalCommas(statement) {
statement += ','; // so I don't have to handle the "last, leftover parameter"
var results = [];
var chars = statement.split('');
var level = 0; // levels of parenthesis, used to track how deep I am in ().
var index = 0; // determines which parameter am I currently on.
var temp = '';
// this is somewhat like your implementation in the edits, I walk through the characters one by one, and do something extra if it's a special character.
chars.forEach(function (char) {
switch (char) {
case '(':
temp += char;
level++;
break;
case ')':
temp += char;
level--;
break;
case ',':
// if the comma is between a set of parenthesis, ignore.
if (level !== 0) { temp += char; }
// if the comma is external, split the string.
else { results[index] = temp; temp = ''; index++; }
break;
default:
temp += char;
break;
}
});
return results;
}
4.)将所有内容放在一起,将字符串语句转换为中间对象:
var str = "a(b, c(e, f(h,i,j), g(k,l,m(o,p,q)) ), d(r,s,t))";
str = processStatement(str);
var root = produceNodeFromStatement(str);
// Output is something like:
{
a: {
b: null,
c: {
e: null,
f: { h: null, i: null, j: null },
g: {
k: null, l: null,
m: { o: null, p: null, q: null }
}
},
d: { r: null, s: null, t: null }
}
}
5.)我假设从现在开始,将这个中间对象映射到您的预期目标是很简单的?您不能对3个值使用相同的属性名称,因此您不能这样做
func:'c',
params:[
{
p:'e',
p:{
func:'f',
params:[
{p:'h'},
{p:'i'},
{p:'j'}
]
},
p:'g',
如果我们删除此部分并修复示例中其他不一致的部分(至少尝试编写一个本身不是失败的示例),那么使用eval将代码转换为javascript就相对容易:
解析器:
var parse = function (str) {
var compiled = str.replace(/(\w+)\s*(\W)/g, function (match, name, token) {
if (token == "(")
return "q(\"" + name + "\",";
else
return "p(\"" + name + "\")" + token;
}).replace(/,\s*\)/g, ")");
function q(name) {
return {
p: {
func: name,
params: Array.prototype.slice.call(arguments, 1)
}
};
}
function p(name) {
return {
p: name
};
}
var f = eval("(function (){return " + compiled + ";})");
return f().p;
};
测试:
注:
我同意Ira Baxter的观点,您必须阅读更多关于如何进行此操作的一般信息。您必须编写一个更复杂的解析器来解析它。通过常规语法,它不是很容易理解的。计算括号嵌套是主要问题。是的,这是我遇到的主要问题。因为要处理数量未知的参数,这就更加困难了。如果有什么想法出现在我脑海中,我洗耳恭听。解析是一个很大的话题,就像,它实际上是一门或多门你在高级计算机科学中学习的课程。这不是非常复杂,但涉及的东西很多。你考虑过吗?这会简单得多。假设字符串是有效的。如果不是,所有的赌注都没有了。
describe("x", function () {
it("y", function () {
var str = "a(b, c(e), d(r,s,t))";
var obj = {
func: 'a',
params: [
{p: "b"},
{
p: {
func: 'c',
params: [
{
p: 'e'
}
]
}
},
{
p: {
func: 'd',
params: [
{p: 'r'},
{p: 's'},
{p: 't'}
]
}
}
]
};
expect(parse(str)).toEqual(obj);
});
});