Search code examples
pythondelimiter

Python - Check that all delimiters are matched and closed


I am trying to write a Python program that takes a string and checks whether all delimiters have been matched and closed.

I found this program that does this, but sadly it does not work for string quotes. Unfortunately I don't completely understand how the program works, so I can't fix it. Can someone tell me how to change the program to work for string delimiters (' and ").

The current code I have is:

delimOpens = ['[', ']', '(', ')', '{', '}', '"', "'"]
delimCloseToOpen = {']':'[', ')':'(', '}':'{', '"':'"', "'":"'"}

def check_match(source):
    delimStack = ['sentinel']
    for c in source:
        if c in delimOpens:
            delimStack.append(c)
        elif c in delimCloseToOpen:
            if delimCloseToOpen[c] != delimStack.pop():
                return False
    return (len(delimStack) == 1)

if __name__ == "__main__":
    print(check_match('{(abc)22}[14(xyz)2]'))
    print(check_match('[ { ] }'))
    print(check_match('{ (x) } ['))
    print(check_match('This is "hello" world'))
    print(check_match('This is "hello world'))

The issue is that the code returns false for the valid string:

print(check_match('This is "hello" world'))

Solution

  • You are pushing a " on the stack even when you encounter a closing ".

    Solution: do an early check if the current character can close something and that something is in the stack top (delimStack[-1]):

    delimOpens = ['[', ']', '(', ')', '{', '}', '"', "'"]
    delimCloseToOpen = {']':'[', ')':'(', '}':'{', '"':'"', "'":"'"}
    
    def check_match(source):
        delimStack = ['sentinel']
        for c in source:
            if c in delimCloseToOpen and delimCloseToOpen[c] == delimStack[-1]:
                delimStack.pop()
            elif c in delimOpens:
                delimStack.append(c)
            elif c in delimCloseToOpen:
                if delimCloseToOpen[c] != delimStack.pop():
                    return False
        return (len(delimStack) == 1)
    
    if __name__ == "__main__":
        print(check_match('{(abc)22}[14(xyz)2]'))
        print(check_match('[ { ] }'))
        print(check_match('{ (x) } ['))
        print(check_match('This is "hello" world'))
        print(check_match('This is "hello world'))
    

    Output:

    $ python3 so_50153245.py
    True
    False
    False
    True
    False