Функция JS для проверки скобок в строке

ребята! Я хочу спросить вас, как сделать функцию, которая проверяет, правильно ли расставлены скобки в строке. Например, "(a + b).4,2 - )c + 5)", и я должен проверить скобки. Я что-то пробовал, но это не работает (извините, я новичок в javascript):

function checkBrackets(str){
	var newOrder = [];
	var bracket1 = "(";
	var bracket2 = ")";
	for(var bracket1 in str){
		
			newOrder.push("1");
	}

	for(bracket2 in str){
		
			newOrder.pop();
	}

	if(newOrder.length == 0){
		console.log("Right!" + newOrder);
	} else{
		console.log("Wrong!" + newOrder);
	}
}

checkBrackets('( ( a + b ) / 5 – d )');

Я попытался перебрать строку с помощью цикла for-in и всякий раз, когда он попадает в «(», чтобы добавить «1» в массив. И когда он попадает в «)», чтобы удалить один «1» из массива. В конце, если массив пуст, я могу сделать вывод, что скобки расставлены правильно, а если нет, то нет.


person Sharen_charshaf    schedule 20.12.2014    source источник
comment
Есть ли конкретная причина, по которой вы используете массив вместо простого счетчика?   -  person JJJ    schedule 20.12.2014
comment
Нет, я просто пошел прямо к массиву... Я не подумал о счетчике. И я вообще новичок в программировании и в javascript.   -  person Sharen_charshaf    schedule 20.12.2014
comment
Может быть, вам стоит попробовать со счетчиком и посмотреть, что получится. Ваша основная проблема с методом массива заключается в том, что вы не можете .pop() пустой массив.   -  person JJJ    schedule 20.12.2014
comment
Идея заключалась в том, что если я добавлю 1, когда появится первая скобка, я уберу ее, если там будет другая. Так что массив не будет пустым   -  person Sharen_charshaf    schedule 20.12.2014
comment
Да, я понимаю. Но когда у вас есть (a + b).4,2 - ), массив будет пустым, когда вы нажмете второй ).   -  person JJJ    schedule 20.12.2014
comment
Я такой тупой facepalm... Ты прав!   -  person Sharen_charshaf    schedule 20.12.2014


Ответы (3)


Вы можете сделать это следующим образом:

// str is the string to parse
function checkBrackets(str){
    // depth of the parenthesis
    // ex : ( 1 ( 2 ) ( 2 ( 3 ) ) )
    var depth = 0;
    // for each char in the string : 2 cases
    for(var i in str){   
        if(str[i] == '('){
            // if the char is an opening parenthesis then we increase the depth
            depth ++;
        } else if(str[i] == ')') {
            // if the char is an closing parenthesis then we decrease the depth
            depth --;
        }  
        //  if the depth is negative we have a closing parenthesis 
        //  before any matching opening parenthesis
        if (depth < 0) return false;
    }
    // If the depth is not null then a closing parenthesis is missing
    if(depth > 0) return false;
    // OK !
    return true;
}
console.log(checkBrackets('( ( a + b ) / 5 – d )')); // true
console.log(checkBrackets('( ( ) a + b ) / 5 – d )')); // false
console.log(checkBrackets('( ) ) ( ( a + b ) / 5 – d )')); // false
person nobe4    schedule 20.12.2014

Хотя вы уже приняли ответ, я почувствовал, что он немного сложен, поэтому я решил расширить наивное решение, которое я представил в комментариях к вопросу:

function checkBrackets(str) {
  // using a regular expression to find the number '(' characters in the string,
  // escaping with a '\' because '(' is a special character within a regular
  // expression; if no matches are found, and the result of 'match()' is falsey,
  // we instead assign an empty array (in order that calling 'length', later, on
  // a potentially-null object, won't create an error):
  var opens = str.match(/\(/g) || [],
    closes = str.match(/\)/g) || [];

  // if there are equal numbers of '(' and ')' characters, we return true,
  // otherwise false:
  return opens.length === closes.length;
}

// unnecessary, this is just a means of iterating over the <li> elements, to work on
// a range of inputs for the function:
Array.prototype.forEach.call(document.getElementsByTagName('li'), function(li) {
  // li is the <li> element/node itself, li.textContent is the text contained within
  // that <li>, using the classList API to add a 'valid' class (if brackets are balanced)
  // or an 'invalid' class (if the brackets are not balanced):
  li.classList.add(checkBrackets(li.textContent) ? 'valid' : 'invalid');
});
ul {
  margin: 0;
  padding: 0;
}
li {
  list-style-type: none;
  margin: 0 0 0.5em 0;
  padding: 0.5em;
  width: 100%;
  box-sizing: border-box;
}
.valid {
  border: 1px solid #0f0;
}
.invalid {
  border: 1px solid #f00;
}
<ul>
  <li>( ( a + b ) / 5 - d )</li>
  <li>( a + b ) / 5 - d</li>
  <li>( a + b ) / ( 5 - d )</li>
  <li>( a + b ) / 5 - d )</li>
  <li>a + b ) / 5 - d</li>
  <li>( a + b / 5 - d</li>
</ul>

Использованная литература:

person David says reinstate Monica    schedule 20.12.2014
comment
Ваше решение интересно, но не охватывает все случаи: jsfiddle.net/okyxvz02 Вот почему я использовал счетчик (чтобы предотвратить закрытие перед открывающей скобкой). - person nobe4; 21.12.2014
comment
Справедливое замечание, но без уточнения вопроса о том, какую проблему (проблемы) он хочет решить, я согласился со своим первоначальным и наивным предположением. - person David says reinstate Monica; 21.12.2014
comment
вы правы, тем временем я обновил свой код некоторыми комментариями. - person nobe4; 21.12.2014

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

function IsValid(text) {
  const leftBraces = [];

  for (let i = 0; i < text.length; i++) {
    const char = text[i];

    switch (Brace(char)) {
      case 'L':
        leftBraces.push(char);
        break;
      case 'R':
        if (!Match(leftBraces.pop() + char)) {
          return false;
        }
        break;
    }
  }

  return leftBraces.length === 0; 
}

function Match(brackets) {
  switch (brackets) {
    case '()': case '{}': case '[]':
      return true;
    default:
      return false;
  }
}

function Brace(c) {
  switch (c) {
    case ')': case '}': case ']':
      return 'R';
    case '(': case '{': case '[':
      return 'L';
    default:
      return ''; 
  }
}

console.log(IsValid('c[d]')) // true
console.log(IsValid('a{b[c]d}e')) // true
console.log(IsValid('a{b(c]d}e')) // false - ] doesn’t match (
console.log(IsValid('a[b{c}d]e}')) // false - nothing matches final }
console.log(IsValid('a{b(c)')) // false - no matching }
person WesleyAC    schedule 20.11.2019