How to change the cycle of getting correct answers?
I have a task to create a function that reverses any string character within a regular sequence of brackets, starting with the innermost pair. The sequence of lines can contain spaces, punctuation marks, letters and marriages. Therefore, the result must be a sting.
Example
For string
s = "a(bc)de"
the output should be
reverseParentheses(s) = "acbde".
To solve this problem, I wrote the following code:
s_i = s
for i in range(s.count('(')):
# reverse letters inside parenthesis
s_i = s_i.replace(s_i[s_i.rindex('(')+1:s_i.index(')')], s_i[s_i.rindex('(')+1:s_i.index(')')][::-1])
# delete outward parenthesis
s_i =s_i[:s_i.rindex('(')] + s_i[s_i.rindex('(')+1:]
# delete inward parenthesis
s_i =s_i[:s_i.index(')')] + s_i[s_i.index(')')+1:]
i += 1
print(s_i)
However, I am getting false results for the following lines:
s = "abc(cba)ab(bac)c"
It should be
abcabcabcabc
I get
abccabbaabcc
AND
s = "The ((quick (brown) (fox) jumps over the lazy) dog)"
It should be like this:
The god quick nworb xof jumps over the lazy
But I only get:
The god quick xof nworb jumps over the lazy
How do I fix or tweak my code to get correct results for the last two examples?
Correction of the code
I tried to take the answers and hints into account, but I couldn't use recursion. I looked into the problem with parameters when there are only two of them:"..(...) (...).., .."
So, I did the following code:
def reverse(s):
#ensure parens are in pairs
if '(' not in s and ')' not in s:
while '(' in s:
s = s.replace(s[s.rindex('(')+1:s.index(')')], s[s.rindex('(')+1:s.index(')')][::-1])
s = s[:s.rindex('(')] + s[s.rindex('(')+1:]
s = s[:s.index(')')] + s[s.index(')')+1:]
return s
else:
if (s[s.index(')'):s.rindex('(')+1] == ''):
while '(' in s:
s = s.replace(s[s.rindex('(')+1:s.index(')')], s[s.rindex('(')+1:s.index(')')][::-1])
s = s[:s.rindex('(')] + s[s.rindex('(')+1:]
s = s[:s.index(')')] + s[s.index(')')+1:]
return s
elif (s[s.index(')'):s.rindex('(')+1] != ''):
betw = s[s.index(')')+1:s.rindex('(')]
part1 = s[:s.index(')')+1]
part2 = s[s.rindex('('):]
part1 = part1.replace(part1[part1.rindex('(')+1:part1.index(')')], part1[part1.rindex('(')+1:part1.index(')')][::-1])
part1 = part1[:part1.rindex(')')]
part2 = part2.replace(part2[part2.rindex('(')+1:part2.index(')')], part2[part2.rindex('(')+1:part2.index(')')][::-1])
part2 = part2[part2.rindex('(')+1:]
s = part1+betw+part2
s = s[:s.rindex('(')] + s[s.rindex('(')+1:]
s = s[:s.index(')')] + s[s.index(')')+1:]
while '(' in s:
s = s.replace(s[s.rindex('(')+1:s.index(')')], s[s.rindex('(')+1:s.index(')')][::-1])
s = s[:s.rindex('(')] + s[s.rindex('(')+1:]
s = s[:s.index(')')] + s[s.index(')')+1:]
return s
else:
while '(' in s:
s = s.replace(s[s.rindex('(')+1:s.index(')')], s[s.rindex('(')+1:s.index(')')][::-1])
s = s[:s.rindex('(')] + s[s.rindex('(')+1:]
s = s[:s.index(')')] + s[s.index(')')+1:]
return s
However, I think it may not work well for the following example:
s = "abc(147)ab(123)c(12)asd"
The answer should be: "abc741ab321c21asd"
but I am getting"abc12c321ba147asd"
What needs to be changed to get the correct answer?
source to share
rather than doing it manually, use a module regexre
that specializes in string handling
import re
def reverseParentheses(s):
def reverse_interior(m):
s = m.group()
return s[-2:0:-1]
old = ""
while old != s:
old = s
s = re.sub(r'(\([^\(\)]*\))',reverse_interior,s)
return s
assert reverseParentheses("a(bc)de") == "acbde"
assert reverseParentheses("abc(cba)ab(bac)c") == "abcabcabcabc"
assert reverseParentheses("The ((quick (brown) (fox) jumps over the lazy) dog)") == "The god quick nworb xof jumps over the lazy"
assert reverseParentheses("((ob))") == "ob"
here the expression '(\([^\(\)]*\))'
will search for everything between (
and )
that is one of the characters defined in [^\(\)]*
, which in turn means any character of numbers that is not (
or )
so it will search for the innermost group that will match, then I am using the re.sub function to replace the ones contained in the string with this helper function that takes a form string "(xyz)"
and returns "zyx"
. Since this is the only job for the inner group itself, the process should be repeated as long as there are changes to be made, hence the cycle.
source to share
The reason your solution doesn't work is because it doesn't match the parentheses:
"abc(cba)ab(bac)c"
" (cba)ab(bac) "
" )ab( "
Your method will ultimately fail: instead, I recommend that you figure out the best way to figure out which pairs match:
def find_paren_set(str):
# magic
return left, right
Once you have this opportunity, you can just while has_parens(str):
until you finish.
Additional note: every time you change a section, the internal partners will be replaced, ((ob))
will become )bo(
.
source to share
Since it seems like there can be any number of pairs ()
, I would recommend implementing a recursive function that can be called as long as the pairs of partners still exist at a level beyond the first:
def reverseParentheses(s):
# ensure parens are in pairs
assert '(' in s and ')' in s
while '(' in s:
# Go through and swap strings/letters in the innermost parens only.
# Then reassign `s` to that newly formatted string
# (after taking out those parens)
# Call the function again until it purges the string of all parens
reverseParentheses(s)
return s
source to share