извлечь некоторую часть кода, избегая непревзойденных скобок другой части - PullRequest
2 голосов
/ 05 мая 2019

Я пытаюсь написать компилятор 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'}
                         }
                    }}}}}))}{`;

Expexted Output:

     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 ]

1 голос
/ 06 мая 2019

Предполагая, что ключи и значения не могут содержать открывающие или закрывающие фигурные скобки, вам просто нужно проигнорировать все перед первой открывающей фигурной скобкой, затем посчитать фигурные скобки (+1 для каждой открывающей фигурной скобки, -1 для каждой закрывающей фигурной скобки), получить индекс последнюю подходящую фигурную скобку затем игнорируйте все после этого.

Этот код работает для тестовых случаев OP, и тесты демонстрируются.

Код, безусловно, потерпит неудачу в крайних случаях, которые могут быть обработаны с помощью дополнительных замен. Этот код определенно потерпит неудачу, если ключи или значения в вашем фрагменте кода содержат открывающие или закрывающие фигурные скобки (чтобы исправить это, вам придется следить за тем, находитесь ли вы в идентификаторе (ключе) или в значении, и игнорировать фигурные или неверные фигурные скобки во время подсчета) .

Так что он будет все больше превращаться в тяжеловесный парсер и не будет очень эффективным.

Я настоятельно рекомендую вам использовать генератор синтаксических анализаторов, например 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'
);
1 голос
/ 06 мая 2019

Для такого типа задач вы должны использовать, например, правило выполнения: просто помните, «голова монеты не может быть выполнена без хвоста, как мальчик не может быть выполнен без девочки, аналогично сравните то же самое, пока вы попадаете в мир кода { не может быть выполнено без }"

Правило: Поместите первое, что должно быть выполнено (т. Е. {), в массив, а на другом шаге, когда найден его противоположный партнер } , оно завершено, поэтому поместите что-то ценное в одно и то же место. .

Если вы не совсем понимаете мое правило, ознакомьтесь со 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));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...