简体   繁体   中英

using a regex to split the parenthesis in a a string

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM