Parse arithmetic string with regular expression
<p>I need to parse an arithmetic string with only <em>times</em> (<code>*</code>) and <em>add</em> (<code>+</code>), e.g., <code>300+10*51+20+2*21</code>, use regular expressions. </p>

<p>I have the working code below: </p>

<pre><code>import re


input_str = '300+10*51+20+2*21'

#input_str = '1*2+3*4'


prod_re = re.compile(r"(\d+)\*(\d+)")
sum_re = re.compile(r"(\d+)\+?")

result = 0
index = 0
while (index &lt;= len(input_str)-1):
    #-----
    prod_match = prod_re.match(input_str, index)
    if prod_match:
        # print 'find prod', prod_match.groups()
        result += int(prod_match.group(1))*int(prod_match.group(2))
        index += len(prod_match.group(0))+1
        continue
    #-----
    sum_match = sum_re.match(input_str, index)
    if sum_match:
        # print 'find sum', sum_match.groups()
        result += int(sum_match.group(1))
        index += len(sum_match.group(0))
        continue
    #-----
    if (not prod_match) and (not sum_match):
        print 'None match, check input string'
        break


print result
</code></pre>

<p>I am wondering if there is a way to avoid creating the variable <code>index</code> above?    </p>

<p>The algorithm seems not correct. An input of <code>1*2+3*4</code> does not yield a correct result. It seems wrong that after resolving one multiplication you continue to resolve an addition, while in some cases you would have to first resolve more multiplications before doing any additions.</p>

<p>With some change in the regular expressions and loops, you can achieve what you want as follows:</p>

<pre><code>import re

input_str = '3+1*2+3*4'

# match terms, which may include multiplications
sum_re = re.compile(r"(\d+(?:\*\d+)*)(?:\+|$)")
# match factors, which can only be numbers 
prod_re = re.compile(r"\d+")

result = 0
# find terms
for sum_match in sum_re.findall(input_str):
    # for each term, determine its value by applying the multiplications
    product = 1
    for prod_match in prod_re.findall(sum_match):
        product *= int(prod_match)
    # add the term's value to the result
    result += product

print (result)
</code></pre>

<h3>Explanation</h3>

<p>This regular expression:</p>

<pre><code>(\d+(?:\*\d+)*)(?:\+|$)
</code></pre>

<p>... matches an integer followed by zero or more multiplications:</p>

<pre><code>(?:\*\d+)*
</code></pre>

<p>The <code>(?:</code> makes it a non-capture group. Without <code>?:</code> the method <code>findall</code> would assign this part of the match to a separate list element, which we don't want.</p>

<p><code>\*\d+</code> is: a literal asterisk followed by digits.</p>

<p>The final <code>(?:\+|$)</code> is again a non-capture group, that requires either a literal <code>+</code> to follow, or the end of the input (<code>$</code>).</p>

python regex math