Is there any recommended way to do multiple string substitutions other than doing replace
chaining on a string (i.e. text.replace(a, b).replace(c, d).repl
How fast? Also, how big are your strings?
There's a fairly simple recipe for building a regular expression to do the job on another site. It might need some tweaking to handle regex metacharacters; I didn't look too closely.
If that's not good enough, you probably need to write some C code, honestly. You can build a simple state machine to do all the replacements, and then process any string byte by byte with no backtracking along the machine to actually do the work. However, I doubt you will beat the regex engine without going to C and optimizing that.
Normally, .replace
method beats all other methods. (See my benchmarks above.)
Something like the following maybe? Split the text into pieces with the first "from" item to be replaced, then recursively split each of those parts into sub-parts with the next "from" item to be replaced, and so on, until you've visited all your replacements. Then join with the "to" replacement item for each as recursive function completes.
A little hard to wrap your head around the following code perhaps (it was for me, and I wrote it), but it seems to function as intended. I didn't benchmark it, but I suspect it would be reasonably fast.
def multi_replace(pairs, text):
stack = list(pairs)
stack.reverse()
def replace(stack, parts):
if not stack:
return parts
# copy the stack so I don't disturb parallel recursions
stack = list(stack)
from_, to = stack.pop()
#print 'split (%r=>%r)' % (from_, to), parts
split_parts = [replace(stack, part.split(from_)) for part in parts]
parts = [to.join(split_subparts) for split_subparts in split_parts]
#print 'join (%r=>%r)' % (from_, to), parts
return parts
return replace(stack, [text])[0]
print multi_replace(
[('foo', 'bar'), ('baaz', 'foo'), ('quux', 'moop')],
'foobarbaazfooquuxquux')
for:
barbarfoobarmoopmoop