Хорошо, вот один из подходов. Идея состоит в том, чтобы использовать более новый модуль регулярных выражений с возможностью пропустить что-либо в скобках (это делается через (*SKIP)(*FAIL)
) и реализовать кортеж с числом, а не только значениями. Наконец, мы используем функцию замены, которая подсчитывает замены:
import regex as re
# make a tuple out of it
d = {
'tREST': ('tu REST', 0),
'FOO': ('fu oop our', 0),
'SHOO': ('Shi Hoo oop our', 0),
'DOOs': ('Doot Ooop Our sour', 0),
'TOP-SHOO': (None, 0)
}
# clear out Nones
for k, v in d.items():
if v[0] is None:
d[k] = (k, 0)
# pattern with r- and f-strings
pattern = re.compile(rf'''
\([^()]+\)(*SKIP)(*FAIL)
|
\b{"|".join(d.keys())}\b
''', re.VERBOSE)
# here comes the magic
def replacer(match):
key = match.group(0)
try:
value, cnt = d[key]
result = value if cnt else key
cnt += 1
d[key] = (value, cnt)
except KeyError:
pass
return result
output = pattern.sub(replacer, s)
print(output)
Немного неясно, как вы хотите обработать, например, bla bla bla (FOO). bla FOO bla bla.
- замените второй FOO
на второй или оставьте его так как в любом случае мы игнорируем что-либо между скобками?
Возможные оптимизации
Вы можете оставить исходный диктат таким, какой он есть, поскольку мы все равно его зацикливаем и затем может сделать кортеж из значений. Это может быть легче поддерживать (добавляя новые заменители, то есть):
# a dict
d = {
'tREST': 'tu REST',
'FOO': 'fu oop our',
'SHOO': 'Shi Hoo oop our',
'DOOs': 'Doot Ooop Our sour',
'TOP-SHOO': None
}
# clear out Nones
for k, v in d.items():
if v is None:
d[k] = (k, 0)
else:
d[k] = (v, 0)