Last active
January 24, 2019 20:45
-
-
Save wtask/fd4471b935fac5dfad3d9067cf2cf66b to your computer and use it in GitHub Desktop.
Check brackets balanced
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package brackets | |
type ( | |
// B - bracketing type; [0] - open, [1] - close. | |
B [2]rune | |
) | |
// Round - return round bracketing type | |
func Round() B { | |
return B{'(', ')'} | |
} | |
// Curly - return curly bracketing type | |
func Curly() B { | |
return B{'{', '}'} | |
} | |
// Square - return square bracketing type | |
func Square() B { | |
return B{'[', ']'} | |
} | |
// IsBalanced - checks string contain balanced set of opening-closing brackets. | |
// For empty string or empty bracketing scope always returns true. | |
func IsBalanced(s string, scope ...B) bool { | |
if s == "" || len(scope) == 0 { | |
return true | |
} | |
expectation := make([]rune, 0, len(scope)) // stacked expectations of closing brackets | |
for _, r := range []rune(s) { | |
for _, b := range scope { | |
if b[0] == b[1] { | |
// invalid bracketing | |
continue | |
} | |
if r == b[0] { | |
// opening | |
expectation = append(expectation, b[1]) | |
break | |
} | |
if r == b[1] { | |
// closing | |
if len(expectation) == 0 || | |
expectation[len(expectation)-1] != r { | |
return false | |
} | |
expectation = expectation[:len(expectation)-1] | |
break | |
} | |
} | |
} | |
return len(expectation) == 0 | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package brackets | |
import "testing" | |
func TestIsBalanced(t *testing.T) { | |
cases := []struct { | |
s string | |
scope []B | |
expected bool | |
}{ | |
{"", []B{}, true}, | |
{"", []B{Round(), Curly(), Square()}, true}, | |
{"][][", []B{}, true}, // empty bracketing scope | |
{"][][", []B{Round()}, true}, // balanced with round brackets, which are absent inside string | |
{"(][][)", []B{Round()}, true}, // balanced with round brackets, square are out of the scope | |
{"(][][)", []B{Round(), Square()}, false}, | |
{"([])", []B{Round(), Square()}, true}, | |
{"([)]", []B{Round(), Square()}, false}, | |
{"(()()(){}", []B{Round(), Square(), Curly()}, false}, | |
{"(()()(){})", []B{Round(), Square(), Curly()}, true}, | |
{"(()()()[{})]", []B{Round(), Square(), Curly()}, false}, | |
{"((((([]))))){{{[]}}}", []B{Round(), Square(), Curly()}, true}, | |
{"({[})]", []B{Round(), Square(), Curly()}, false}, | |
{"{ { { { { } } } } } word() [inside]", []B{Round(), Square(), Curly()}, true}, | |
{"<><{}>(<...>)<[]>", []B{Round(), Square(), Curly(), B{'<', '>'}}, true}, | |
{"])([", []B{B{']', '['}, B{')', '('}}, true}, // brainfuck brackets | |
{"])[(", []B{B{']', '['}, B{')', '('}}, false}, | |
{"[(])", []B{B{'\x00', '\x00'}}, true}, // invalid brackets (opening == closing) are ignored | |
{"\x00[(])\x00", []B{B{'\x00', '\x00'}, Round(), Square()}, false}, // invalid brackets (opening == closing) are ignored | |
} | |
for _, c := range cases { | |
if actual := IsBalanced(c.s, c.scope...); actual != c.expected { | |
t.Errorf("IsBalanced() != %v for %q and %q", c.expected, c.s, c.scope) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment