in reply to Replace strings with 
I seem to recall someone saying at one point that it's a rite of passage, everyone implements a templating language, usually badly. It starts out simple enough, but then grows into some unmaintainable behemoth that is inconsistent, slow, and ugly.
So, what I'm trying to say, is that if you have any control over that string, try re-using existing templating languages instead of inventing your own. Depending on what you're doing, you may find this actually is more expensive than doing it yourself. But, in my experience, that doesn't hold true for long. The cost of adding features to a hand-rolled templating system that weren't thought of when you started can grow very quickly.
At $work, in my current project, I elected to do a hybrid. At first, I simply used my own templating code due to legal reasons (getting legal approval to ship wasn't going to be soon enough). However, I wrote it to work with the subset of Template Toolkit that was sufficient for my needs at the time. By the time I needed more, I had legal approval to use and ship Template Toolkit (under the Artistic license), and none of my templates needed changing, while I simply had to swap out my code for the more generic Template Toolkit, and I got all the extra features I needed (and many more I didn't ... yet).
So, even if you don't want to go full-tilt into a module's template code, may I at least suggest being compatible with the subset of the language you do need? It'll make it easier to switch should you ever need more, and may make other things more obvious. Such as using [% random_hash("a") %] instead of just a?
Of course, maybe you have no control or influence over your input, and that's unfortunate. In that case, continue with your current approach. Just be aware that if you have different keys of different length and some may be subsets of another, you'll also want to sort them by length and try the longest ones first. (This isn't always straightforward if your match strings actually have variable length modifiers, such as * or ? in there.) And, of course, if a's result includes "a" in its output, things can get wonky (though you said that a would result in a number, so you should be fine with the example data).