You could take advantage that the match sets the (thread local) $~ (also known as $LAST_MATCH_INFO if you use the English module), so this seems to work. 

#!/usr/bin/env ruby

require 'English'

pattern = /
(?<lq>
 %7B                        # single left brace, followed by
 %(?:25|(?![A-Fa-f0-9]{2})) # plaintext '%' or encoded as %25
)
|                            # or
(?<rq>
 %(?:25|(?![A-Fa-f0-9]{2})) # plaintext '%' or encoded as %25
 %7D                        # followed by right brace
)
/x

string = "%7B% test %%7D"
replacements = { 'lq' => '{%', 'rq' => '%}' }

puts string.gsub(pattern) {
  matched_name = $LAST_MATCH_INFO.names.find { |n| $LAST_MATCH_INFO[n] }
  replacements[matched_name]
}      

produces:

~/tmp  ruby try.rb
{% test %}

Hope this helps,

Mike

On Apr 15, 2014, at 7:32 PM, Andrew Vit <andrew / avit.ca> wrote:

> On 14-04-15, 16:28, Andrew Vit wrote:
>>     replacements = {'\k<lq>' => '{{', '\k<rq>' => '}}'}
> >      expected = "{% string %}"
> 
> Oops: replacements = {'\k<lq>' => '{%', '\k<rq>' => '%}'}
> 
> Andrew Vit

-- 

Mike Stok <mike / stok.ca>
http://www.stok.ca/~mike/

The "`Stok' disclaimers" apply.