Reputation: 51
I am writing a program to reverse the substrings enclosed in parenthesis in python. The resultant string should not contain any parenthesis. I am printing b1 and b2 and ch for testing purposes. It seems that in the second iteration of the for loop inside the while loop, the b1 variable is not updated with the correct index. I tried to write a solution like below:
def reverseParentheses(s):
r = s
sstring = ''
astring = ''
b1 = b2 = 0
count = 0
for ch in s:
if ch == '(':
count+=1
elif ch ==')':
count+=1
else:
pass
while True:
b1 = b2 = 0
for ch in r:
if ch == '(':
b1 = r.index(ch)
print("b1= ",b1, ch)
if ch == ')':
b2 = r.index(ch)
print("b2= ",b2, ch)
sstring = r[b2-1:b1:-1]
print(r)
print(sstring)
astring = r[0:b1]+sstring+r[b2+1:]
print(astring)
r = astring
break
if len(astring)+count == len(s):
break
return r
s = "a(bcdefghijkl(mno)p)q"
print(reverseParentheses(s))
This is the output that I get: aonmpbcdefghijklq This is the output I expect: apmnolkjihgfedcbq
Upvotes: 4
Views: 806
Reputation: 92430
A nice way to deal with nested delimiters is to use a stack. When you encounter an opening delimiter push a new collection to the stack. pop()
when you find a closing. This will keep the order of nesting correct.
Here's one way to do this (it doesn't check for balanced parenthesis, but it's not hard to add):
s = "a(bcdefghijkl(mno)p)q"
stack = [[]] # accumulate letters in stack[0]
for l in s:
if l == '(':
stack.append([]) # start a new level
elif l == ')':
sub = stack.pop()[::-1] # pop the last level and reverse
stack[-1].extend(sub) # add to current
else:
stack[-1].append(l) # add to current
''.join(stack[0]) #'apmnolkjihgfedcbq'
Upvotes: 6
Reputation: 4137
A method by finding the position of the parenthesis and reversing from inside out (so the ones that are contained in-between an even number of parenthesis stay the same) and finally gets rid of the parenthesis:
s = "a(bcdefghijkl(mno)p)q"
leftp = reversed([pos for pos, char in enumerate(s) if char == "("])
rightp = [pos for pos, char in enumerate(s) if char == ")"]
for i in zip(leftp,rightp):
subs = s[i[0]+1:i[1]][::-1]
s = s[:i[0]+1]+subs+s[i[1]:]
for c in ["(", ")"]:
s = s.replace(c, "")
print(s) # Outputs "apmnolkjihgfedcbq"
EDIT
For parenthesis that are not nested, as pointed out by .@Mark Meyer, you can find them as described here and same rule applies
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
s = "a(bcd)efghijkl(mno)pq"
parens = find_parens(s)
for leftp, rightp in parens.items():
subs = s[leftp+1:rightp][::-1]
s = s[:leftp+1]+subs+s[rightp:]
for c in ["(", ")"]:
s = s.replace(c, "")
print(s) # Outputs "adcbefghijklonmpq"
Upvotes: 1