4

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

6
  • what is your expected output? Commented Nov 30, 2018 at 6:43
  • It outputs this: b1= 1 ( b1= 1 ( b2= 17 ) a(bcdefghijkl(mno)p)q onm(lkjihgfedcb aonm(lkjihgfedcbp)q b1= 4 ( b2= 17 ) aonm(lkjihgfedcbp)q pbcdefghijkl aonmpbcdefghijklq aonmpbcdefghijklq. The last line is the end result of the program Commented Nov 30, 2018 at 6:45
  • find parens index on the deepest nested paren level, reverse chars in between, repeat until no parens left Commented Nov 30, 2018 at 6:47
  • 1
    don't answer in comments, edit your question to include the expected output and actual output Commented Nov 30, 2018 at 6:48
  • Yes, that is the correct assessment of the problem. Commented Nov 30, 2018 at 6:57

2 Answers 2

6

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'
Sign up to request clarification or add additional context in comments.

Comments

1

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" 

3 Comments

seems problematic with strings like: s = "(ab)cdefghijklmno(pq)" --> "conmlkjihgfedcbadefghijklmnopq"
More robust than yours now hehe :P
Seems pretty bulletproof now.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.