i need to split the parenthesis of a polynomial, something like this.
'ac*(ab+(2ab+4ac))'
--> ['ac*',['ab+',['2ab+4ac']]]
.
i tried using this regex but there is something wrong. \[[^\]]*\]|\([^\)]*\)|\"[^\"]*\"|\S+
Edit 2,
Translation of @Cary Swoveland's Ruby code to Python to demo the recursive way to do this as well!
def polyparse(string):
start_idx = 0
curr_idx = 0
arr = []
while curr_idx != len(string):
try:
lft_idx = string.index('(', curr_idx)
except ValueError:
arr.append(string[curr_idx:len(string)+1])
break
if lft_idx > curr_idx:
arr.append(string[curr_idx:lft_idx])
rt_idx = find_matching(string, lft_idx+1)
# code here to raise exception if rt_idx.nil?
if rt_idx > lft_idx + 2:
arr.append(polyparse(string[lft_idx+1:rt_idx]))
curr_idx = rt_idx + 1
return arr
def find_matching(string, start_idx):
nbr_unmatched = 0
for i in range(start_idx, len(string)):
c = string[i]
if c == ')':
if nbr_unmatched == 0:
return i
nbr_unmatched = nbr_unmatched - 1
if c == '(':
nbr_unmatched = nbr_unmatched + 1
return None
print(polyparse("ac*(ab+(2ab+4ac))"))
print(polyparse("ac*(ab+(2ab+4*(ac+bd)))+((x+2)*3)"))
Returns:
['ac*', ['ab+', ['2ab+4ac']]]
['ac*', ['ab+', ['2ab+4*', ['ac+bd']]], '+', [['x+2'], '*3']]
Edit 1, original method wouldn't work on more complex polynomials, thank you @Cary Swoveland for pointing that out, Similar idea though as before: convert it to a string rep and then use json to safely parse to list:
import json
import re
def to_list(polynomial_exp):
v = '[' + ''.join([x.replace('(', '[').replace(')', ']' ) for x in [x if re.search(r'(\(|\))', x) else ',"' + x + '",' for x in [x for x in re.split(r'(\(|\))', polynomial_exp) if x != '']]]) + ']'
return json.loads(v.replace('[,', '[').replace(',]', ']'))
# original example:
to_list('ac*(ab+(2ab+4ac))')
# more complex example:
to_list("ac*(ab+(2ab+4*(ac+bd)))+((x+2)*3)")
Output:
>>> to_list('ac*(ab+(2ab+4ac))')
['ac*', ['ab+', ['2ab+4ac']]]
>>> to_list("ac*(ab+(2ab+4*(ac+bd)))+((x+2)*3)")
['ac*', ['ab+', ['2ab+4*', ['ac+bd']]], '+', [['x+2'], '*3']]
Assuming the strings can have arbitrary levels of nested parentheses, I don't believe that a regular expression is the right tool to produce the desired array. Not knowing Python, I am offering a (recursive) solution in Ruby. As the two languages are similar in many ways I am hopeful that a reader will offer a Python solution using an algorithm similar to the one I've employed. (Even readers who don't know Ruby can probably figure out my algorithm.) I will delete my answer if and when a Python solution along these lines is posted.
def polyparse(str)
start_idx = 0
curr_idx = 0
arr = []
loop do
return arr if curr_idx == str.size
lft_idx = str.index('(', curr_idx)
return arr << str[curr_idx..-1] if lft_idx.nil?
arr << str[curr_idx..lft_idx-1] if lft_idx > curr_idx
rt_idx = find_matching(str, lft_idx+1)
# code here to raise exception if rt_idx.nil?
arr << polyparse(str[lft_idx+1..rt_idx-1]) if rt_idx > lft_idx + 2
curr_idx = rt_idx + 1
end
end
def find_matching(str, start_idx)
nbr_unmatched = 0
(start_idx..str.size-1).each do |i|
c = str[i]
case c
when ')'
return i if nbr_unmatched.zero?
nbr_unmatched -= 1
when '('
nbr_unmatched += 1
end
end
nil
end
polyparse("ac*(ab+(2ab+4ac))")
#=> ["ac*", ["ab+", ["2ab+4ac"]]]
polyparse("ac*(ab+(2ab+4*(ac+bd)))+((x+2)*3)")
#=> ["ac*", ["ab+", ["2ab+4*", ["ac+bd"]]], "+", [["x+2"], "*3"]]
See String#index with particular reference to the second (optional) argument.
Note:
str = "ac*(ab+(2ab+4ac))"
01234567890123456
^ ^
^ ^
find_matching(str, 3+1) #=> 16
find_matching(str, 7+1) #=> 15
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.