Как правильно использовать re.sub для поиска и замены слов в файле
ЗАДАЧА
Заменить в файле все слова, которые начинаются с 'l_' или 's_' или 'i_' или 'b_' или 'h_' или 'sA_' или 'iA_' или 'lA_' или 'bA_' или 'nA_' или 'f' или 'n' (пример - l_ChangePlane) на случайный набор английских букв. Сохранив (если имеется) "<< >>", "()". Но если в слове присутствует "@usr_", то надо сохранить "@". Нельзя изменять слова "job_name" и "blknum_f" Если слова повторяются, они должны быть заменены одним "шифром" .
ПРИМЕРЫ
Было: iA_Hours<<i_DefTool>>
Должно стать: poiuybrntfsgybrn<< pqbcfrzdenmkgcasr>>
Было: @usr_SpecCharChange(job_name)
Должно стать: @oplaghftybndrtcy(job_name)
Что не так?
СЛОВА, НАЧИНАЮЩИЕСЯ С "l_", "s_", "i_" и т.д. ОСТАЮТСЯ НЕЗАМЕНЁННЫМИ
Было: Ai_hours
Должно стать: jhfytryqnegtfgco (или другой рандомный набор букв)
.
КОД
import random
import re
changed_vars = dict()
special_words = ['blknum_f', 'job_name']
prefixes = ['l_', 's_', 'i_', 'b_', 'h_', 'sA_', 'iA_', 'lA_', 'bA_', 'nA_', 'n_']
suffixes = ['_f']
def generate_word(length=16):
alphabet = 'qwertyuiopasdfghjklzxcvbnm'
return ''.join(random.choice(alphabet) for _ in range(length))
# Заменяет переменную на случайное слово, если она не была заменена ранее.
def replace_var(var, changed_vars):
if var.startswith('@usr_'):
base = '@'
var = var[1:] # удаляем @, чтобы не заменять его
else:
base = ''
if var not in changed_vars:
changed_vars[var] = generate_word()
return base + changed_vars[var]
# Обрабатывает строку, заменяя переменные внутри кавычек "<<>>", круглых скобок "()", а также переменные, соответствующие условиям, и переменные, начинающиеся с "@usr_".
def process_line(line, changed_vars):
def replacer(match):
var = match.group(0)
return replace_var(var, changed_vars)
if line not in special_words:
# Обрабатываем переменные с кавычками << >>
line = re.sub(r'<<.*?>>', lambda m: '<<' + replace_var(m.group(0)[2:-2], changed_vars) + '>>', line)
# Обрабатываем переменные в круглых скобках
line = re.sub(r'\(.*?\)', lambda m: '(' + replace_var(m.group(0)[1:-1], changed_vars) + ')', line)
# Обрабатываем переменные, соответствующие условиям
# ЭТО УСЛОВИЕ НЕ ВЫПОЛНЯЕТСЯ И СЛОВА, НАЧИНАЮЩИЕСЯ С "l_", "s_", "i_" и т.д. ОСТАЮТСЯ НЕЗАМЕНЁННЫМИ
line = re.sub(r"(?<!@usr_)(\bl_\b|\bs_\b|\bi_\b|\bb_\b|\bh_\b|\bsA_\b|\biA_\b|\blA_\b|\bbA_\b|\bnA_\b|\b_f\b|\bn_\b)", replacer, line)
# Обрабатываем переменные, начинающиеся с @usr_
line = re.sub(r'@usr_\w+', replacer, line)
return line
result = []
changed_vars = dict()
with open("путь", "r", encoding="utf-8") as file:
for line in file:
processed_line = process_line(line, changed_vars)
result.append(processed_line)
with open("путь", 'w', encoding="utf-8") as file:
file.writelines(result)
print(result)
Для поиска и замены переменных использованы регулярные выражения (re.sub).
Ответы (1 шт):
Ваш код не работает потому, что ваше регулярное выражение неправильное:
r"(?<!@usr_)(\bl_\b|\bs_\b|\bi_\b|\bb_\b|\bh_\b|\bsA_\b|\biA_\b|\blA_\b|\bbA_\b|\bnA_\b|\b_f\b|\bn_\b)"
Если это расшифровать: <граница слова><одно из условий><граница слова>
. Оно будет совпадать с любым словом, которое равно условию, но не со словом, где после условия есть другие буквы.
Например, эти слова - s_
, sA_
будут заменены, но не эти s_hello
, sA_hi
.
Вам необходимо использовать что-то вроде этого:
r'\b(l_|s_|i_|b_|h_|sA_|iA_|lA_|bA_|nA_|n_|_f|usr_)[a-zA-Z]*\b'
Что можно расшифровать: <граница слова><одно из условий><остальные буквы или пустая строка><граница слова>
.
И, наконец, итоговый результат:
import random
import re
import string
search_pattern = re.compile(
r'\b(l_|s_|i_|b_|h_|sA_|iA_|lA_|bA_|nA_|n_|_f|usr_)[a-zA-Z]*\b'
)
def replace(target_string: str) -> str:
def replacer(match_obj: re.Match) -> str:
key = match_obj.group()
sub_str_len = len(match_obj.group())
if key not in cache:
cache[key] = ''.join(
random.choices(string.ascii_lowercase, k=sub_str_len)
)
return cache[key]
cache = {}
return search_pattern.sub(replacer, target_string)