Как закрыть все открытые теги и добавить открывающие всем закрывающим, у которых нет пары?
Есть строка, содержащая произвольный набор скобок (тегов): ()((())[[[[]}}{.
Нужно проверить, есть ли у каждой открывающей скобки закрывающая ее пара, если нет то поставить.
И наоборот если в строке есть закрывающая скобка без открывающей ее пары, то нужно перед ней добавить открытие.
То есть, если наша строка выглядела вот так:()((())[[[[]}}{ то надо сделать ()((()))[[[[]]]]{{}}{};
Методом гугления нашел только, как проверить такую строку на то, чтобы все скобки имели закрывающую пару.
написал следующую функцию, но желаемого результата не получил
jQuery(function($) {
$('input').click(function() {
var string_array = ('()((()))[[[[]{{}}{').split('');
console.log(close_tags(string_array, 0, string_array.length));
});
let openedtags = {
"[": "]",
"{": "}",
"(": ")",
}; //тег открыт
let closedtags = { //открывающие пары для закрывающих тегов
"]": "[",
"}": "{",
")": "(",
}
let opentags = [];
function close_tags(string_array, i, len) {
if (len > i) {
if (openedtags[string_array[i]]) { //если тег открыт
opentags.push(string_array[i]); //запоминаем его
i = i + 1;
close_tags(string_array, i, len); //и переходим к следующему тегу
} else { //если тег закрыт
//смотрим совпадает ли открывающий парный эемент с поледним в массиве
if (opentags[opentags.length - 1] == closedtags[string_array[i]]) { //если совпал
opentags.pop(); //удаляем из массива
i = i + 1;
close_tags(string_array, i, len); //и переходим к следующему тегу
} else { //если нет
string_array.splice(i - 1, 0, closedtags[string_array[i]]); //добавляем перед ним открывающую пару
i = i + 2;
close_tags(string_array, i, len); //и переходим к следующему тегу
}
}
} else {
opentags.reverse().forEach(function(tag) {
string_array.push(closedtags[tag]);
})
}
return string_array.join("");
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
<input type="submit" value="Поехали">
Ответы (2 шт):
const source = '[{[({]';
const OPENED_BRACKETS = {
"[": "]",
"{": "}",
"(": ")",
};
const CLOSED_BRACKETS = {
"]": "[",
"}": "{",
")": "(",
};
function closeBrackets(sourceString, openedBrackets, i) {
if (i < sourceString.length) {
if (OPENED_BRACKETS[sourceString[i]]) {
openedBrackets.push(sourceString[i]);
closeBrackets(sourceString, openedBrackets, i + 1)
} else {
if (openedBrackets[openedBrackets.length - 1] === CLOSED_BRACKETS[sourceString[i]]) {
openedBrackets.pop();
closeBrackets(sourceString, openedBrackets, i + 1)
} else {
sourceString.splice(i, 0, CLOSED_BRACKETS[sourceString[i]]);
closeBrackets(sourceString, openedBrackets, i + 2)
}
}
} else {
openedBrackets.reverse().forEach(function(item) {
sourceString.push(OPENED_BRACKETS[item])
});
}
return sourceString.join('')
}
console.log(closeBrackets(source.split(''), [], 0));
Решил сначала разобраться с половиной задачи: Научиться хотя бы закрывать все открытые скобки слева направо, а лишние закрывающие не трогать. После чего можно отзеркалить строку и повторить процедуру.
let test = [
"()((())[[[[]}}{{{",
"(((())]}]}[]}{[]}",
"([]([]][][][][[}}",
"(a)a(a(a(a)a)a[a[a[a[a]a}a}a{a",
].map(e => e + " >>> " + autoCorrect(e));
console.log(test);
/***/
function autoCorrect(str) {
let _o = new Lib();
str = _o.mirror(correctToLeft(str));
return _o.mirror(correctToLeft(str)).join("");
/***/
function correctToLeft(str) {
let result = [];
for (let char of str) {
if ( _o.isClosing(char) ) {
if ( _o.openingPair(char) === _o.stackLast() ) {
_o.openingStack.pop();
} else {
result = result.concat( _o.getStackCloser({clear: true}) );
}
} else if ( _o.isOpening(char) ) {
_o.openingStack.push(char);
}
result.push(char);
}
return result.concat( _o.getStackCloser({clear: true}) );
}
/*****/
function Lib() {
this.pair = {
"{": "}",
"}": "{",
"(": ")",
")": "(",
"[": "]",
"]": "[",
};
this.openingStack = [];
this.getStackCloser = function({
clear
}) {
let str = this.openingStack.map(scope => this.pair[scope]).slice().reverse();
if (clear) this.openingStack = [];
return str;
}
this.stackLast = () => this.openingStack[this.openingStack.length - 1];
this.isClosing = (char) => /\]|\}|\)/.test(char);
this.isOpening = (char) => /\[|\{|\(/.test(char);
this.openingPair = (char) => this.pair[char];
this.mirror = function(arr) {
return arr.slice().reverse().map(char => this.pair[char] || char);
}
}
}