title: In python, how to use regex to conditionally pattern match
body: <p>I am trying to parse the following string with python's regex library:</p>
  
  <pre><code>recipe_a = 'run_list[sm_collectd::default@1.0.0]'
  </code></pre>
  
  <p>Using <a href="http://pythex.org/" rel="nofollow noreferrer">http://pythex.org/</a>, I am trying out the following regexes:</p>
  
  <pre><code>\[(.*)::(.*)@(.*)\]
  </code></pre>
  
  <p>Which yields:</p>
  
  <pre><code>Match 1
      1.  sm_collectd
      2.  default
      3.  1.0.0
  </code></pre>
  
  <p><strong>Here is the problem:</strong></p>
  
  <p>recipe_a can be pattern matched with this regex, however, it fails when the <strong>@version</strong> is no longer specified in the string. The following example will fail to match the pattern:</p>
  
  <pre><code>recipe_b = 'run_list[sm_collectd::default]'
  </code></pre>
  
  <p><code>\\[(.\*)::(.\*)@(.\*)\\]</code> fails in this case because @ was never matched. have python logic that trys <code>\\[(.\*)::(.\*)@(.\*)\\]</code> and tries the latter regex <code>\\[(.\*)::(.\*)\\]</code>. But that would be silly. It would be nice if I could accomplish this in one regex pattern.</p>
  
  <p>I have tried solving this with a conditional regex statement. The general syntax I have tried is as follows:</p>
  
  <pre><code>(?(?=regex)then|else)
  </code></pre>
  
  <p>the first ? is lookahead assertion: matches without consuming. So we could have a conditional match on the <code>@</code> symbol. </p>
  
  <p>if the <code>@</code> is matched then do <code>\\[(.\*)::(.\*)@(.\*)\\]</code>, else do <code>\\[(.\*)::(.\*)\\]</code>.</p>
  
  <p><strong>PROGRAMATIC SOLUTION</strong></p>
  
  <pre><code>kitchen_recipe = 'recipe[my_cookbook::default@0.1.0]'
  
  recipe = kitchen_recipe.strip('recipe[').strip(']')
  if '@' in recipe:
      cookbook, recipe, cookbook_version = tuple(re.split('::|@', recipe))
  else:
      cookbook, recipe = tuple(re.split('::', recipe))
      cookbook_version = None   # no version specified
  </code></pre>
  
  <p><strong>REGEX SOLUTION</strong></p>
  
  <pre><code>kitchen_recipe = 'recipe[my_cookbook::default@0.1.0]'
  
  run_list_pattern = '\[(.*)::([^@]*)@?([0-9.]*)\]'
  cookbook, recipe, cookbook_version = re.search(test_list_pattern,
                                                 kitchen_recipe).groups()
  </code></pre>