title: Replace matches according to the pattern that was matched
body: <p>Given a set of regular expressions, is there a simple way to match multiple patterns, and replace the matched text according to the pattern that was matched?</p>
  
  <p>For example, for the following data <code>x</code>, each element begins with either a number or a letter, and ends with either a number or a letter. Let's call these patterns <code>num_num</code> (for begins with number, ends with number), <code>num_let</code> (begins with number, ends with letter), <code>let_num</code>, and <code>let_let</code>.</p>
  
  <pre><code>x &lt;- c('123abc', '78fdsaq', 'aq12111', '1p33', '123', 'pzv')
  type &lt;- list(
    num_let='^\\d.*[[:alpha:]]$',
    num_num='^\\d(.*\\d)?$',
    let_num='^[[:alpha:]].*\\d$',
    let_let='^[[:alpha:]](.*[[:alpha:]])$'
  )
  </code></pre>
  
  <p>To replace each string with the name of the pattern it follows, we could do:</p>
  
  <pre><code>m &lt;- lapply(type, grep, x)
  rep(names(type), sapply(m, length))[order(unlist(m))]
  ## [1] "num_let" "num_let" "let_num" "num_num" "num_num" "let_let"
  </code></pre>
  
  <p>Is there a more efficient approach?</p>
  
  <hr>
  
  <h3><code>gsubfn</code>?</h3>
  
  <p>I know that with <code>gsubfn</code> we can simultaneously replace different matches, e.g.:</p>
  
  <pre><code>library(gsubfn)
  gsubfn('.*', list('1p33'='foo', '123abc'='bar'), x)
  ## [1] "bar"     "78fdsaq" "aq12111" "foo"     "123"     "pzv"
  </code></pre>
  
  <p>but I'm not sure whether the replacements can be made dependent on the <em>pattern that was matched</em> rather than on the match itself.</p>
  
  <hr>
  
  <h3><code>stringr</code>?</h3>
  
  <p><code>str_replace_all</code> doesn't play nicely with this example, since matches are replaced for patterns iteratively, and we end up with everything being overwritten with <code>let_let</code>:</p>
  
  <pre><code>library(stringr)
  str_replace_all(x, setNames(names(type), unlist(type)))
  ## [1] "let_let" "let_let" "let_let" "let_let" "let_let" "let_let"
  </code></pre>
  
  <p>Reordering <code>type</code> so the pattern corresponding to <code>let_let</code> appears first solves the problem, but needing to do this makes me nervous.</p>
  
  <pre><code>type2 &lt;- rev(type)
  str_replace_all(x, setNames(names(type2), unlist(type2)))
  ## [1] "num_let" "num_let" "let_num" "num_num" "num_num" "let_let"
  </code></pre>