提取代码的某些部分,避免其他部分不匹配的花括号

时间:2019-05-05 12:00:25

标签: javascript object

我正在尝试编写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的完整属性

请帮助我

2 个答案:

答案 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'
);