Найти отсутствующие фигурные скобки в строке javascript

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

Это то, что я написал

function checkParanthesis(str){
  var depth=0;
  for(var i in str){
    if(str[i] == "(" || str[i] == "{" || str[i] == "[")
      depth++;
    else if(str[i] == ")" || str[i] == "}" || str[i] == "]")
      depth--;
  }
  
  if(depth !==0) return false;
  
  return true;
}

console.log(checkParanthesis("() test"));

Ответы

Ответ 1

Используйте массив как стек, чтобы отслеживать неразрешенные скобки открывания:

function checkParanthesis(str){
  var stack=[];
  for(var i=0; i<str.length; i++){
    if(str[i] == "(" || str[i] == "{" || str[i] == "[")
      stack.push(str[i]);
    else if(str[i] == ")") {
        if(stack.pop() != "(") { return false; }
    }
    else if(str[i] == "}") {
        if(stack.pop() != "{") { return false; }
    }
    else if(str[i] == "]") {
        if(stack.pop() != "[") { return false; }
    } 
  }

  return !stack.length;
}

Вы можете, возможно, очистить это, чтобы быть более читабельным, но в основном:

  • Каждый раз, когда вы находите открытую фигуру, добавьте ее в стек.
  • Каждый раз, когда вы видите закрывающуюся фигурную скобку, поместите стек и посмотрите, соответствует ли верхняя часть стека подходящей открытой скобкой.
    • Если это не так, у вас есть несоответствие, поэтому вы можете сразу вернуться false.
  • Если вы дойдете до конца, вы не заметили никаких ошибок, верните true, если стек пуст (т.е. stack.length есть 0).

(Примечание. Я также изменил ваш цикл i in str, поскольку он будет перебирать свойства на String.prototype.)

Одна очистка, которую вы могли бы сделать (но я не уверен, что это делает код более удобочитаемым или нет), заключалось бы в том, чтобы поставить пары привязок в объект с закрывающим символом в качестве ключа и соответствующего начального символа в качестве стоимость. Затем посмотрите, существует ли текущий символ в качестве ключевого объекта in, и если это так, поместите стек и посмотрите, соответствует ли значение для этого ключа:

function checkParanthesis(str){
  var stack=[];
  var brace_pairings = { ")":"(", "}":"{", "]":"[" };
  for(var i=0; i<str.length; i++){
    if(str[i] == "(" || str[i] == "{" || str[i] == "[") {
      stack.push(str[i]);
    } else if(str[i] in brace_pairings) {
        if(stack.pop() != brace_pairings[str[i]]) { return false; }
    }
  }

  return !stack.length;
}

Ответ 2

Вместо счетчика вы можете использовать стек, нажимая токен в стек, когда открывается открывающая скобка, и выскакиваете из стека, когда видна правильная закрывающая скобка. Если закрывающая скобка встречается, когда другой тип скобки находится в верхней части стека или когда стек пуст, строка является дисбалансом.

Что-то вроде этого (не отполировано и проверено):

function checkParanthesis(str){
var stack = [];
var open;
for(var i in str){
  if(str[i] == "(" || str[i] == "{" || str[i] == "[") {
    stack.push(str[i]);
  }
  else if(str[i] == ")" || str[i] == "}" || str[i] == "]") {
    if ( stack.length == 0 ) {
       return false;
    }
    open = stack.pop();
    if (
       ( open == '(' && str[i] != ')' )
       || ( open == '[' && str[i] != ']' )
       || ( open == '{' && str[i] != '}' )
     ) {
       return false;
    }
  }
}

 if ( stack.length > 0 ) {
   return false;
 }

 return true;
}

Ответ 3

Используйте регулярное выражение для получения всех фигурных скобок в массиве match()... затем удалите каждый конец массива, проверяя каждый набор

function checkParanthesis(str) {
  //hashmap to compare open/close braces
  var closers = {'[': ']','(': ')','{': '}'};
  // create braces array
  var parStack = str.match(/\(|\{|\[|\)|\}|\]/g) || [];

  if (parStack.length % 2 !== 0) {//must have even number
    return false;
  } else {
    while (parStack.length) {
      // check each end of array against each other.
      if (closers[parStack.shift()] !== parStack.pop()) {
        //mismatch , we're done
        return false;
      }
    }
    return true;
  }

}
console.log('no braces ', checkParanthesis("test"));
console.log('matched ', checkParanthesis("() test"));
console.log('mis matched ',checkParanthesis("[(]) abcd")); // should return false
console.log('matched ',checkParanthesis("[{()}] test"));

Ответ 4

Подход массива/стека/счетчика читает строку слева направо. Другой подход - работать изнутри.

function checkParanthesis(str){
  while ( str.indexOf('()')>=0 || str.indexOf('[]')>=0 || str.indexOf('{}')>=0 ) {
    str = str.replace('()','').replace('[]','').replace('{}','');
  }
  return str.length===0;
}

Вы можете использовать регулярные выражения для замены, чтобы сделать глобальную замену и цикл меньше раз. Недостатком является то, что вам нужно избегать всего в поле зрения: str.replace(/\(\)/g,'') et.c.