 <p>You should go with the second approach.</p> <p>One possible solution is a greedy algorithm. Define your set of transformations as a regular expression (used to test the pattern) and a function which is given the regexp match object and returns the transformed string.</p> <p>Regular expressions aren't quite powerful enough to handle what you want directly. Instead you'll have to do something like:</p> <pre><code>m = re.match(r"C\[(\d+)\]H\[(\d+)]\]", formula) if m: C_count, H_count = int(m.group(1)), int(m.group(2)) match_size = len(m.group(0)) if C_count*2+2 == H_count: replacement = alkane_lookup[C_count] elif C_count*2 == H_count: replacement = alkene_lookup[C_count] ... else: replacement = m.group(0) # no replacement available </code></pre> <p>(plus a lot more for the other possibilities)</p> <p>then embed that in a loop which looks like:</p> <pre><code>formula = "...." new_formula = "" while formula: match_size, replacement = find_replacement(formula) new_formula += replacement formula = formula[match_size:] </code></pre> <p>(You'll need to handle the case where nothing matches. One possible way is to include a list of all possible elements at the end of find_replacement(), which only returns the next element and counts.)</p> <p>This is a greedy algorithm, which doesn't guarantee the smallest solution. That's more complicated, but since chemists themselves have different ideas of the right form, I wouldn't worry so much about it.</p>