Skip to content

Instantly share code, notes, and snippets.

@ramonrails
Last active January 8, 2024 19:08
Show Gist options
  • Save ramonrails/578917d502d997527c60944c83edcfa5 to your computer and use it in GitHub Desktop.
Save ramonrails/578917d502d997527c60944c83edcfa5 to your computer and use it in GitHub Desktop.
Matching brackets problem - with multiple bracket types
// Goal: find matching enclosures
// * opening enclosure must appear before closing
// * multiple opening enclosures can appear, but must be closed in proper reverse order
// * any other text, character ot symbol should not affect the result
// * pre or post padding space or characters should not affect the result
const balanced = (string) => {
// example: { "{}": 0, "[]": 0, ...}
let enclosures = { "{}": 0, "[]": 0, "()": 0, "<>": 0 }
// stack of keys must match closing braces in the reverse order
let stack = []
// iterate and check each character
for (const char of string) {
// if we already have -1, skip the loop
if (Object.values(enclosures).includes(-1)) continue
// iterate for each pair of `enclosures`
for (const [key, value] of Object.entries(enclosures)) {
// when we have an opening enclosure to match
// note the `^` sign in regex
//
if (key.match(new RegExp("^\\" + char, "g"))) {
// remember the enclosure that the next cycle will match now
stack.push(key)
// because the opening matched, increment the counter
enclosures[key] = value + 1;
// cut the run short, check next
break
} else
// when we have a closing enclosure to match
// note the `$` sign in regex
//
if (key.match(new RegExp("\\" + char + "$", "g"))) {
// we found the closing of the last opening enclosure
if (stack.at(-1) === key) {
// ready to track any enclosure again
stack.pop()
// decrease the counter for this enclosure
enclosures[key] = value - 1
// cut the run short, check next
break
}
// last key not matched?
// this closing is different from the last opening enclosure
else {
// mark the last key as a mis-match
enclosures[stack.at(-1)] = -1
// fail fast
break
}
}
} // -- for entries()
} // -- for chars array
// This is balanced when all values are ZERO
//
return (Object.values(enclosures) || []).every(value => value === 0) ? "Matching" : "Naa!"
}
// test cases
//
[
"()", "([{<>}])", "<>(){}[]", // Balanced
")(", "(()", "(])", "{[}]", "( () [{ }] )", // Nah!
"no paranthesis", "", // no enclosures? consider Balanced
"complex ( set of [paranthesis] <nested> ( at many levels{ here } ))" // nested and balanced
].map((arg) => {
console.log(balanced(arg) + ' <= ' + arg)
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment