Perhaps try using the undocumented re.Scanner:
import re
scanner = re.Scanner([
(r"[\\]", r'\\textbackslash{}'),
(r"[{]", r'\\{{}'),
(r"[}]", r'\\}{}'),
(r".", lambda s, t: t)
])
tokens, remainder = scanner.scan("\\foo\\{bar}")
print(''.join(tokens))
yields
\\textbackslash{}foo\\textbackslash{}\\{{}bar\\}{}
Unlike the code you posted, if you look at the source code, the re.Scanner.scan makes only one pass through the string. Once a match is made, the next match is begun from where the last match ended.
The first argument to re.Scanner
is a lexicon
-- a list of 2-tuples. Each 2-tuple is a regex pattern and an action. The action may be a string, a callable (function), or None
(no action).
The patterns are all compiled into one compound pattern. So the order in which the patterns are listed in the lexicon is important. The first pattern to match wins.
If a match is made, the action is called if it is callable, or simply returned if a string. The return values are collected in the list tokens
.