我正在尝试编写JavaScript编译器,在这里我需要处理很多编程符号,因此我的程序要比其他程序复杂一些。我在字符串形式的变量 a 中有一段不完整的代码,我想提取 @style 的完整属性,以避免向后不相关的符号并将其转换为纯对象不完整的对象(实际上是一个字符串)。如果您不理解,请查看下面的输出示例;
我已经尝试了很多次,但是由于缺乏解决此类问题的概念,我无法解决,请帮助我。
var a = `@style":{".time":{color:"red"}}}`;
var b = `@style":{".time":{color:"red" , height:'10px'}}}}}}))}`;
var b = `@style":{".time":{
color:"red" ,
height:'10px'
},
"@keyframes example" : {
"0%" : {background-color: 'red'},
"25%" : {background-color: 'yellow'}
}
}}}}}))}{`;
扩展输出:
a = {".time":{color:"red"}}
b = {".time":{color:"red" , height:'10px'}}
c = {
".time":{
color:"red" ,
height:'10px'
},
"@keyframes example" {
"0%" : {
background-color: "red"
},
"25%" : {
background-color: "yellow"
}
}
}
在示例中,您可以清楚地看到仅使用括号}和{相互对应,但是避免了没有相应的打开/关闭括号的括号。
为了清楚地理解问题:
让我们假设变量 a , b 和 c 包含完整的对象,我需要从中提取 @style的完整属性。
请帮助我
答案 0 :(得分:1)
对于这种类型的问题,您必须使用履行规则,例如:请记住,“硬币的头不能没有尾巴就无法实现,男孩没有女孩也无法实现,同样,当您进入代码世界时,同样的事情也要<如果没有} “
,就无法实现strong> {规则:将要完成的第一件事(即 {)放置在数组中,而在找到对立伙伴} 的另一步骤中,则将其完成,因此将一些有价值的数据放入同一地方。
如果您不清楚我的规则,请查看100%工作代码。
var out = console.log ,
a = `@style":{".time":{
color:"red" ,
height:'10px'
},
"@keyframes example" : {
"0%" : {background-color: 'red'},
"25%" : {background-color: 'yellow'}
}
}}}}}))}{`,
a = a.substr(a.indexOf(':')+1).replace(/\s/g,''),
state = [],
Endpoint = -1,
found = function(state , index){
for(var i = 0 ; i < state.length ; i++){
if(state[i] == '{'){
state[i] = index;
FirstEntry = true;
break;
}
}
},
check = function(state){
for(var j = 0 ; j < state.length ; j++){
if(typeof state[j] !== 'number'){
return(0);
}
}
return(1);
};
for(var i = 0 ; i < a.length ; i++){
var el = a[i];
if(el == '{'){
state.push(el);
}
if(el == '}'){
found(state , i);
}
if(check(state)){
Endpoint = i;
break;
}
}
out(Endpoint , a.substr(0,Endpoint+1));
答案 1 :(得分:1)
假设键和值不能包含左括号或右括号,则只需要在首先打开括号之前忽略所有内容,然后计算括号(每个左括号为+1,每个右括号为-1),然后检索最后一个匹配的花括号,然后忽略之后的所有内容。
此代码适用于OP测试用例,并演示了测试。
代码在某些情况下肯定会失败,可以通过其他替换来处理。 如果代码摘录中的键或值包含左括号或右括号,则该代码肯定会失败(以解决在标识符(键)或值中必须跟踪的问题,并在计数期间忽略inkey或invalue括号)
因此它将越来越多地成为重量级的解析器,并且效率不高。
我强烈建议您尝试使用PEGJS之类的解析器生成器,而不要尝试解析自己。编译本身是一个难题,无需添加解析复杂性...
无论如何,下面的工作示例:
var a = `@style":{".time":{color:"red"}}}`;
var b = `@style":{".time":{color:"red" , height:'10px'}}}}}}))}`;
var c = `@style":{".time":{
color:"red" ,
height:'10px'
},
"@keyframes example" : {
"0%" : {background-color: 'red'},
"25%" : {background-color: 'yellow'}
}
}}}}}))}{`;
// Expexted Output :
test_a = {".time":{color:"red"}};
test_b = {".time":{color:"red" , height:'10px'}};
test_c = {
".time": {
color:"red" ,
height:'10px'
},
"@keyframes example": {
"0%" : {
"background-color": "red"
},
"25%" : {
"background-color": "yellow"
}
}
};
function parseChunk(chunk) {
// trim everything before first brace
var parsedChunk = chunk.replace(/^[^{]*/, '');
// iterate over string, counting braces,
// count++ when encountering {,
// count -- when encountering '}',
// break when count === 0
var braceCount = 0;
var matchingBraceIndex = 0;
for(; matchingBraceIndex < parsedChunk.length; matchingBraceIndex++) {
var c = parsedChunk.charAt(matchingBraceIndex);
if (c === '{') {
braceCount++;
} else if (c === '}') {
braceCount--;
}
if (braceCount === 0) break;
};
if (braceCount !== 0) {
throw new Error('incomplete expression');
}
// trim content after last brace matching first brace
parsedChunk = parsedChunk.substr(0, matchingBraceIndex + 1);
// double quote identifiers
parsedChunk = parsedChunk.replace(/(\s*|{|,)([\w-]+)(\s*:)/g, '$1"$2"$3');
// convert single quote values to double quote values
parsedChunk = parsedChunk.replace(/(\s*|{|,)("[\w-]+")(\s*:\s*)'((?:\\'|[^'])+)'/g, '$1$2$3"$4"');
// the JSON should be parseable now
try {
return JSON.parse(parsedChunk);
} catch (error) {
throw new Error(`unparseable JSON, improve replace rules?\n$${error}`);
}
}
console.log(
parseChunk(a),
" => ",
JSON.stringify(parseChunk(a)) === JSON.stringify(test_a) ? 'OK' : 'NOK'
);
console.log(
parseChunk(b),
" => ",
JSON.stringify(parseChunk(b)) === JSON.stringify(test_b) ? 'OK' : 'NOK'
);
console.log(
parseChunk(c),
" => ",
JSON.stringify(parseChunk(c)) === JSON.stringify(test_c) ? 'OK' : 'NOK'
);