import os
# Папка, которую чиним
ROOT = r'C:\path\to\broken\folder'
# Пары кодировок для попытки: (как читается сейчас -> как должно быть)
# Порядок перебора — от самой частой к редкой
ENCODING_PAIRS = [
('latin-1', 'utf-8'), # Привет -> Привет
('cp1251', 'utf-8'),
('cp866', 'cp1251'),
('cp1251', 'cp866'),
('latin-1', 'cp1251'),
('utf-8', 'cp866'),
]
def fix_name(name):
"""Пробуем декодировать имя в разных кодировках."""
for src, dst in ENCODING_PAIRS:
try:
fixed = name.encode(src).decode(dst)
# Проверка: имя не должно содержать "мусорных" символов
if fixed != name and all(ord(c) >= 32 for c in fixed):
return fixed
except (UnicodeEncodeError, UnicodeDecodeError):
continue
return None
def rename_bottom_up(root):
# Сначала собираем всё дерево
all_paths = []
for dirpath, dirnames, filenames in os.walk(root, topdown=False):
for name in filenames + dirnames:
all_paths.append(os.path.join(dirpath, name))
# topdown=False уже даёт порядок снизу вверх
renamed = 0
for path in all_paths:
if not os.path.exists(path):
continue
dirname, basename = os.path.split(path)
fixed = fix_name(basename)
if fixed and fixed != basename:
new_path = os.path.join(dirname, fixed)
try:
os.rename(path, new_path)
print(f'OK: {basename!r} -> {fixed!r}')
renamed += 1
except OSError as e:
print(f'FAIL: {basename!r} ({e})')
print(f'\nВсего переименовано: {renamed}')
if __name__ == '__main__':
rename_bottom_up(ROOT)