Skip to content

Instantly share code, notes, and snippets.

@Xophmeister
Last active August 4, 2016 20:55
Show Gist options
  • Select an option

  • Save Xophmeister/522786172bd179106569d0905fc7c7c3 to your computer and use it in GitHub Desktop.

Select an option

Save Xophmeister/522786172bd179106569d0905fc7c7c3 to your computer and use it in GitHub Desktop.
Check for balanced parentheses recursively
import unittest
from enum import Enum
from typing import List, Union
class Parens(Enum):
brace = '()'
curly = '{}'
square = '[]'
def eat(paren_stack:List[Parens], data:List[str]) -> bool:
# Non-empty input list
if data:
head, *tail = data
# Check to see if the head character is a parenthesis
found_open, found_closed = (False, False)
for paren in Parens:
open_paren = paren.value[0]
close_paren = paren.value[1]
if head == open_paren:
found_open = paren
break
if head == close_paren:
found_closed = paren
break
# Add the newest found opening parenthesis to the stack
if found_open:
paren_stack.append(found_open)
# Check our closed parenthesis matches the current
if found_closed:
if not paren_stack:
# Mismatched: Nothing to close
return False
current_paren = paren_stack.pop()
if found_closed != current_paren:
# Mismatched: Unbalanced
return False
# Advance
return eat(paren_stack, tail)
# Empty input list
else:
# Mismatch if paren_stack is non-empty: Something still to close
return False if paren_stack else True
def is_valid(data:Union[List[str], str]) -> bool:
if isinstance(data, str):
data = list(data)
return eat([], data)
class TestValidator(unittest.TestCase):
def test_validator(self):
tests = {
'': True,
'()': True,
'[]': True,
'{}': True,
'(foo)': True,
'([])': True,
'{([])}': True,
'{}()[]': True,
'{ [ () ()]}': True,
'(': False,
'{': False,
'[': False,
'(]': False,
'[ ) { ]': False
# More test cases...
}
for test, expected in tests.items():
self.assertEqual(is_valid(test), expected)
if __name__ == '__main__':
unittest.main()
@Xophmeister
Copy link
Author

Xophmeister commented Aug 4, 2016

I'm not convinced that this can't be done without using a stack (e.g., like how a recursive-descent parser works)...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment