Проверьте, сбалансированы ли кавычки и скобки

1

Существует несколько решений о том, как проверить, сбалансированы ли скобки, но я не нашел ни одного, который будет проверять как для сбалансированных котировок, так и для круглых скобок.

Я безуспешно пытался адаптировать это решение (codereview - сбалансированные круглые скобки), чтобы проверить, сбалансированы ли кавычки и скобки.

Например, это должно быть несбалансированным ("back-to-school)"

Исходный код:

function parenthesesAreBalanced(string) {
  var parentheses = "[]{}()",
    stack = [],
    i, character, bracePosition;

  for(i = 0; character = string[i]; i++) {
    bracePosition = parentheses.indexOf(character);

    if(bracePosition === -1) {
      continue;
    }

    if(bracePosition % 2 === 0) {
      stack.push(bracePosition + 1); // push next expected brace position
    } else {
      if(stack.length === 0 || stack.pop() !== bracePosition) {
        return false;
      }
    }
  }

  return stack.length === 0;
}

Мой код - в основном похожий, но добавил несбалансированную проверку котировок.

function areQuotesAndParenthesesBalanced(s: string): boolean {
  const parens = '[]{}()',
      parensStack = [];
  let index, char, numOfQuotes = 0;

  for (index = 0; char = s[index++];){
      const bracePosition = parens.indexOf(char);
      let braceType;

    if (bracePosition === -1 && char !== '"')
        continue;

    braceType = bracePosition % 2 ? 'closed' : 'open';

    //check for double quotes mixed with parentheses
    if(char === '"'){
        const lastInStack = parensStack[parensStack.length - 1];

        numOfQuotes++;

        if(lastInStack === '"'){
            numOfQuotes--;
            parensStack.pop();
        }else if(numOfQuotes > 0 && lastInStack !== '"'){
            return false;
        }else{
            parensStack.push('"');
        }
    }

    if (braceType === 'closed') {
        if (!parensStack.length || parens.indexOf(parensStack.pop()) != bracePosition - 1)
            return false;
    } else {
        parensStack.push(char);
    }
}

//If anything is left on the stack <- not balanced
return !parensStack.length;
}

Для меня довольно сложно определить, какой лучший подход. С круглыми скобками вы всегда знаете, когда кто-то открыт или закрыт, с кавычками, не так много.

  • 1
    Решение должно быть одинаковым независимо от того, какой символ вы используете, просто также проверяет кавычки так же, как вы проверяли бы скобки
  • 2
    @Mitchel0022 Mitchel0022 - я уже пробовал это, и оно не работает из-за того, как оригинальное решение проверяет открытые закрытые скобки - вы не можете определить, открывается ли котировка или нет, используя ту же логику.
Показать ещё 3 комментария
Теги:
algorithm

3 ответа

1
Лучший ответ

Это выполняет проверку для push() или pop() of " двумя способами.

  • Если стек пуст или последний символ в стеке не равен ", тогда вставьте это " в стек ".

  • Если стек не пуст, а последний символ в стеке равен ", то pop() " сам стек ". Это делается потому, что я делаю вид жадного соответствия здесь, так как " для уже стека " означает выражение внутри "...". Таким образом, мы в безопасности, чтобы сопоставить эти 2 " и приступим к следующему.

Хорошо работает, но дайте мне знать, если это не поможет в любом случае.

function areQuotesAndParenthesesBalanced(s){
	var pairs = {
		'}':'{',
		']':'[',
		')':'(',
	};

	var stack = [];

	for(var i = 0;i < s.length;++i){
		switch(s.charAt(i)){
			case '[': case '{':case '(':
				stack.push(s.charAt(i));
			break;
			case ']': case '}':case ')':
				if(isStackEmpty(stack) || peek(stack) !== pairs[s.charAt(i)]) return false;
				stack.pop();
			break;
			case '"':
				if(isStackEmpty(stack) || peek(stack) !== s.charAt(i)){
					stack.push(s.charAt(i));
				}else{
					stack.pop();
				}
		}
	}

	return isStackEmpty(stack);
}

function isStackEmpty(s){
	return s.length === 0;
}

function peek(s){
	return s[s.length-1];
}


var tests = {
				'("back-to-school")':true,
				'"(back-to-school)"':true,
				'("back-to-school)"':false,
				'("back-to-school)':false,
				'"["["["[]"]"]"]"':true,
				'"["]""':false,
				'"[]"""':true,
				'""""':true,
				'""':true,
				'"':false,
				'""[("")]""':true,
				'""[("")]':true,
				'"["["["[]"]"[""]]"]':false,
				'"[]"[({})]""':true,
				'"[{}"]':false
			};

for(var each_test in tests){
	var res = areQuotesAndParenthesesBalanced(each_test);
	console.log(each_test + " --> " + (res === tests[each_test] ? "ok" : "not ok") + " , expected : " + tests[each_test]);
}

ВЫХОД

("back-to-school") --> ok , expected : true
"(back-to-school)" --> ok , expected : true
("back-to-school)" --> ok , expected : false
("back-to-school) --> ok , expected : false
"["["["[]"]"]"]" --> ok , expected : true
"["]"" --> ok , expected : false
"[]""" --> ok , expected : true
"""" --> ok , expected : true
"" --> ok , expected : true
" --> ok , expected : false
""[("")]"" --> ok , expected : true
""[("")] --> ok , expected : true
"["["["[]"]"[""]]"] --> ok , expected : false
"[]"[({})]"" --> ok , expected : true
"[{}"] --> ok , expected : false
  • 1
    Спасибо за это решение - я провел несколько тестов со своими данными и не видел никаких проблем.
  • 0
    @ codeepic Отлично. Спасибо за обновления :)
Показать ещё 2 комментария
2

function tokensAreBalanced(string) {
  var asymmetricTokens = "[]{}()",
    symmetricTokens = '"',
    stack = [],
    i, character, tokenPosition;

  for(i = 0; character = string[i]; i++) {
    tokenPosition = asymmetricTokens.indexOf(character);

    if(tokenPosition >= 0) {
      if(tokenPosition % 2 === 0) {
        stack.push(asymmetricTokens[tokenPosition + 1]); // push next expected token
      } else if(stack.length === 0 || stack.pop() !== character) {
        return false;
      }
    } else {
      if(symmetricTokens.includes(character)) {
        if(stack.length > 0 && stack[stack.length - 1] === character) {
          stack.pop();
        } else {
          stack.push(character);
        }
      }
    }
  }

  return stack.length === 0;
}


console.log('("back-to-school)"', tokensAreBalanced('("back-to-school)"'));

console.log('("back-to-school)', tokensAreBalanced('("back-to-school)'));

console.log('("back-to-school")', tokensAreBalanced('("back-to-school")'));

console.log('(ele AND car) OR ("ele car)")', tokensAreBalanced('(ele AND car) OR ("ele car)")'));
  • 0
    Мне нравится ваше решение - мне потребовалось некоторое время, чтобы понять логику с продолжениями и тот факт, что вы храните braceIndexes в стеке вместо реальных скобок. И вы решили вообще не хранить кавычки в стеке - выбрав логический флаг. Умная. Как вы пришли к этому решению? Меня действительно раздражает, что я не могу разобраться в голове, чтобы придумать алгоритм проверки как паренов, так и кавычек.
  • 1
    @ codeepic Я думаю, что возможно много точных решений, поскольку это зависит от того, как мы интерпретируем выражение. Давайте возьмем ""[("")]"" например. Первый подход, мы можем прочитать это как "" , [("")] , "" . Второй подход заключается в том, что мы можем интерпретировать это как " "[("")]" " что, когда мы рассматриваем " как начало или конец, они могут изменяться и все же быть правильными.
Показать ещё 6 комментариев
2

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

[(,"],
[",)],
[(,"],
[",)]

== ("")("") example of a balanced stack.

[",(],
[",(],
[),"],
[),"]

== "("()")" another balanced stack


[(,"],
[),"]

== (")" trivial unbalanced stack

[(,)] <- trivial item, can ignore in implementation
[","] <- trivial item, can ignore in implementation

[",(],
[),(],
[),"]

== "()()" balanced stack

Я слишком устал, чтобы на самом деле реализовать это, но, надеюсь, это дало вам некоторые идеи и иллюстративные примеры, я пересматриваю его после того, как я посплю.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню