Indices of matching parentheses in Python
Question:
Is there a way to get indices of matching parentheses in a string? For example for this one:
text = 'aaaa(bb()()ccc)dd'
I’d like to get a dictionary with values:
result = {4:14, 7:8, 9:10}
which means that parentheses on index 4 and 14 are matching , 7 and 8 an so on.
Thanks a lot.
Answers:
The standard way to check for balanced brackets is to use a stack. In Python, this can be done by appending to and popping from a standard list:
text = 'aaaa(bb()()ccc)dd'
istart = [] # stack of indices of opening parentheses
d = {}
for i, c in enumerate(text):
if c == '(':
istart.append(i)
if c == ')':
try:
d[istart.pop()] = i
except IndexError:
print('Too many closing parentheses')
if istart: # check if stack is empty afterwards
print('Too many opening parentheses')
print(d)
Result:
In [58]: d
Out[58]: {4: 14, 7: 8, 9: 10}
You mean an automated way?
I don’t think so.
You need to create a program using a stack, in which you push the index when you find an open parenthesis, and pop it when you find a closing parenthesis.
In Python, you can easily use a list as a stack, since they have the append()
and pop()
methods.
def find_parens(s):
toret = {}
pstack = []
for i, c in enumerate(s):
if c == '(':
pstack.append(i)
elif c == ')':
if len(pstack) == 0:
raise IndexError("No matching closing parens at: " + str(i))
toret[pstack.pop()] = i
if len(pstack) > 0:
raise IndexError("No matching opening parens at: " + str(pstack.pop()))
return toret
Hope this helps.
Try this also.
def match(str):
stack = []
ans = {}
for i,ch in enumerate(str):
if ch == "(":
stack.append(i)
else :
try:
if ch == ")":
ans[stack.pop()] = i
continue
except:
return False
if len(stack) > 0:
return False
else:
return ans
test_str = "()"
print(match(test_str))
A bit late to the game but was looking for an alternative/shorter way of finding matching parenthesis….came up with this:
def matching_parentheses(string, idx):
if idx < len(string) and string[idx] == "(":
opening = [i for i, c in enumerate(string[idx + 1 :]) if c == "("]
closing = [i for i, c in enumerate(string[idx + 1 :]) if c == ")"]
for i, j in enumerate(closing):
if i >= len(opening) or j < opening[i]:
return j + idx + 1
return -1
So you can do something like
result = {}
for i, j in enumerate(text):
if j=='(':
result[i] = matching_parentheses(text, i)
print(result)
Which produces
{4: 14, 7: 8, 9: 10}
Edit…here’s an updated version which returns the dict directly:
def matching_parentheses(string):
opening = []
mydict = {}
# loop over the string
for i,c in enumerate(string):
# new ( found => push it to the stack
if c == '(':
opening.append(i)
# new ) found => pop and create an entry in the dict
elif c==')':
# we found a ) so there must be a ( on the stack
if not opening:
return False
else:
mydict[opening.pop()] = i
# return dict if stack is empty
return mydict if not opening else False
or a more condensed version could be
def matching_parentheses(string):
op= []
dc = {
op.pop() if op else -1:i for i,c in enumerate(string) if
(c=='(' and op.append(i) and False) or (c==')' and op)
}
return False if dc.get(-1) or op else dc
And now you can do
text = 'aaaa(bb()()ccc)dd'
m = matching_parentheses(text)
print(m)
This is what I’m using to find the closing bracket of a dictionary so that I can pull it out of a text string and load it as a json object:
test = 'sdfasdfasdfs{ ffasdf{ daf{}}dsdfds}sdfs'
items = []
start = 0
for i,c in enumerate(test):
if c =='{':
if start == 0:
start = i
start += 1
items.append(i)
if c == '}':
items.pop()
if len(items) == 0 and start >0:
print(f"found the end {c}, {i}")
break
Is there a way to get indices of matching parentheses in a string? For example for this one:
text = 'aaaa(bb()()ccc)dd'
I’d like to get a dictionary with values:
result = {4:14, 7:8, 9:10}
which means that parentheses on index 4 and 14 are matching , 7 and 8 an so on.
Thanks a lot.
The standard way to check for balanced brackets is to use a stack. In Python, this can be done by appending to and popping from a standard list:
text = 'aaaa(bb()()ccc)dd'
istart = [] # stack of indices of opening parentheses
d = {}
for i, c in enumerate(text):
if c == '(':
istart.append(i)
if c == ')':
try:
d[istart.pop()] = i
except IndexError:
print('Too many closing parentheses')
if istart: # check if stack is empty afterwards
print('Too many opening parentheses')
print(d)
Result:
In [58]: d
Out[58]: {4: 14, 7: 8, 9: 10}
You mean an automated way?
I don’t think so.
You need to create a program using a stack, in which you push the index when you find an open parenthesis, and pop it when you find a closing parenthesis.
In Python, you can easily use a list as a stack, since they have the append()
and pop()
methods.
def find_parens(s):
toret = {}
pstack = []
for i, c in enumerate(s):
if c == '(':
pstack.append(i)
elif c == ')':
if len(pstack) == 0:
raise IndexError("No matching closing parens at: " + str(i))
toret[pstack.pop()] = i
if len(pstack) > 0:
raise IndexError("No matching opening parens at: " + str(pstack.pop()))
return toret
Hope this helps.
Try this also.
def match(str):
stack = []
ans = {}
for i,ch in enumerate(str):
if ch == "(":
stack.append(i)
else :
try:
if ch == ")":
ans[stack.pop()] = i
continue
except:
return False
if len(stack) > 0:
return False
else:
return ans
test_str = "()"
print(match(test_str))
A bit late to the game but was looking for an alternative/shorter way of finding matching parenthesis….came up with this:
def matching_parentheses(string, idx):
if idx < len(string) and string[idx] == "(":
opening = [i for i, c in enumerate(string[idx + 1 :]) if c == "("]
closing = [i for i, c in enumerate(string[idx + 1 :]) if c == ")"]
for i, j in enumerate(closing):
if i >= len(opening) or j < opening[i]:
return j + idx + 1
return -1
So you can do something like
result = {}
for i, j in enumerate(text):
if j=='(':
result[i] = matching_parentheses(text, i)
print(result)
Which produces
{4: 14, 7: 8, 9: 10}
Edit…here’s an updated version which returns the dict directly:
def matching_parentheses(string):
opening = []
mydict = {}
# loop over the string
for i,c in enumerate(string):
# new ( found => push it to the stack
if c == '(':
opening.append(i)
# new ) found => pop and create an entry in the dict
elif c==')':
# we found a ) so there must be a ( on the stack
if not opening:
return False
else:
mydict[opening.pop()] = i
# return dict if stack is empty
return mydict if not opening else False
or a more condensed version could be
def matching_parentheses(string):
op= []
dc = {
op.pop() if op else -1:i for i,c in enumerate(string) if
(c=='(' and op.append(i) and False) or (c==')' and op)
}
return False if dc.get(-1) or op else dc
And now you can do
text = 'aaaa(bb()()ccc)dd'
m = matching_parentheses(text)
print(m)
This is what I’m using to find the closing bracket of a dictionary so that I can pull it out of a text string and load it as a json object:
test = 'sdfasdfasdfs{ ffasdf{ daf{}}dsdfds}sdfs'
items = []
start = 0
for i,c in enumerate(test):
if c =='{':
if start == 0:
start = i
start += 1
items.append(i)
if c == '}':
items.pop()
if len(items) == 0 and start >0:
print(f"found the end {c}, {i}")
break