Здесь есть две проблемы
- правильное чтение и запись данных
- сохранение структуры
чтение и запись
Согласно Википедии , файлы .nfo этого типа кодируются текстовой кодировкой cp437. Поэтому эта кодировка должна быть указана при чтении и записи файла.
with open('colors.nfo', 'r', encoding='cp437') as f:
...
with open('colors.nfo', 'w', encoding='cp437') as f:
...
В качестве альтернативы, файл может быть открыт в двоичном режиме, и все операции выполняются с использованием байтов, а не текста.
with open('colors.nfo', 'rb') as f:
...
Если кодировка не указана, Python использует системное значение по умолчанию, в данном случае, вероятно, cp1252. 8-битное кодирование, такое как cp1252, может декодировать файл, но где cp437 декодирует b'\xdb'
как «FULL BLOCK» (█), cp1252 декодирует его как 'LATIN CAPITAL LETTER U WITH CIRCUMFLEX' (Û), искажая данные, как видно из вопроса.
Сохранение структуры
Данные имеютФормат с фиксированной шириной, поэтому при замене текста необходимо соблюдать осторожность, чтобы строки назначения и замены имели одинаковую длину, иначе столбцы не будут правильно выровнены.
target = '%REPLACE1%'
replacement = 'BLACKGREY'
delta = len(target) - len(replacement)
padding = ' ' * abs(delta)
if delta > 0:
replacement += padding
else:
target += padding
Решения
Вот полный сценарий.
replacements = {
'%REPLACE1%': 'BLACKGREY',
'%REPLACE2%': 'REDWHITE',
}
with open('colors.nfo', encoding='cp437') as f:
data = f.read()
for target, replacement in replacements.items():
delta = len(target) - len(replacement)
padding = ' ' * abs(delta)
if delta > 0:
replacement += padding
else:
target += padding
data = data.replace(target, replacement)
with open('new-colors.nfo', 'w', encoding='cp437') as f:
f.write(data)
Обработка как двоичных данных одинакова, за исключением того, что файлы открываются и закрываются в двоичном режиме, иtrings объявляются как bytes
, а не str
.
replacements = {
b'%REPLACE1%': b'BLACKGREY',
b'%REPLACE2%': b'REDWHITE',
}
with open('colors.nfo', 'rb') as f:
data = f.read()
for target, replacement in replacements.items():
delta = len(target) - len(replacement)
padding = b' ' * abs(delta)
if delta > 0:
replacement += padding
else:
target += padding
data = data.replace(target, replacement)
with open('new-colors.nfo', 'wb') as f:
f.write(data)