Последняя активность 3 weeks ago

Версия e7428f22c55cbea8607efdf86d675bfc6ececbd0

fix_mojibake.py Исходник
1#!/usr/bin/env python3
2import sys
3import os
4import argparse
5from pathlib import Path
6"""
7Сделано для Димы Андреева, конвертор индексов HTTrack.
8
9Твой файл на самом деле уже в UTF-8, но содержит испорченные символы (mojibake). Это типичная ситуация, когда UTF-8 текст был прочитан как ISO-8859-1.
10"""
11
12def fix_mojibake_utf8(input_path, output_path=None):
13 """
14 Исправляет текст, который был сохранён как UTF-8, но прочитан как ISO-8859-1
15 """
16 try:
17 # Читаем файл как бинарный
18 with open(input_path, 'rb') as f:
19 raw_bytes = f.read()
20
21 # Исправляем mojibake
22 fixed_text = raw_bytes.decode('utf-8').encode('latin-1').decode('utf-8')
23
24 return fixed_text
25
26 except UnicodeDecodeError:
27 # Если не получается исправить как mojibake, пробуем прочитать как обычный UTF-8
28 try:
29 with open(input_path, 'r', encoding='utf-8') as f:
30 return f.read()
31 except:
32 with open(input_path, 'r', encoding='latin-1') as f:
33 return f.read()
34 except Exception as e:
35 print(f"✗ Ошибка при обработке {input_path}: {e}")
36 return None
37
38def process_file(input_file, output_file):
39 """Обрабатывает один файл"""
40 fixed_text = fix_mojibake_utf8(input_file)
41 if fixed_text is None:
42 return False
43
44 # Записываем исправленный текст
45 with open(output_file, 'w', encoding='utf-8') as f:
46 f.write(fixed_text)
47
48 return True
49
50def process_directory(input_dir, prefix="_"):
51 """Обрабатывает все HTML файлы в каталоге"""
52 input_dir = Path(input_dir)
53
54 if not input_dir.exists():
55 print(f"✗ Каталог не найден: {input_dir}")
56 return False
57
58 if not input_dir.is_dir():
59 print(f"✗ Это не каталог: {input_dir}")
60 return False
61
62 # Ищем все HTML файлы
63 html_files = list(input_dir.glob("*.html")) + list(input_dir.glob("*.htm"))
64
65 if not html_files:
66 print(f"✗ В каталоге {input_dir} не найдено HTML файлов")
67 return False
68
69 print(f"Найдено {len(html_files)} HTML файлов для обработки")
70 print("-" * 50)
71
72 processed = 0
73 for input_file in html_files:
74 # Создаем имя выходного файла с префиксом
75 output_file = input_file.with_name(f"{prefix}{input_file.name}")
76
77 print(f"Обработка: {input_file.name}{output_file.name}")
78
79 if process_file(input_file, output_file):
80 processed += 1
81 else:
82 print(f" ✗ Ошибка при обработке {input_file.name}")
83
84 print("-" * 50)
85 print(f"✓ Обработано файлов: {processed}/{len(html_files)}")
86 return True
87
88def main():
89 parser = argparse.ArgumentParser(
90 description='Исправляет mojibake (UTF-8, прочитанный как Latin-1) в файлах'
91 )
92 parser.add_argument('input', help='Входной файл или каталог')
93 parser.add_argument('output', nargs='?', help='Выходной файл (только для обработки одного файла)')
94 parser.add_argument('--prefix', default='_', help='Префикс для обработанных файлов (по умолчанию: _)')
95
96 args = parser.parse_args()
97
98 input_path = Path(args.input)
99
100 # Проверяем, является ли вход каталогом
101 if input_path.is_dir():
102 print(f"📁 Обработка каталога: {input_path}")
103 process_directory(input_path, args.prefix)
104 else:
105 # Обработка одного файла
106 if not input_path.exists():
107 print(f"✗ Файл не найден: {input_path}")
108 sys.exit(1)
109
110 if not args.output:
111 print("✗ Для обработки одного файла нужно указать выходной файл")
112 print("Использование: python script.py input.html output.html")
113 sys.exit(1)
114
115 print(f"📄 Обработка файла: {input_path}")
116 if process_file(input_path, args.output):
117 print(f"✓ Файл сохранен: {args.output}")
118
119 # Показываем превью
120 with open(args.output, 'r', encoding='utf-8') as f:
121 content = f.read(500)
122 print("\nПревью (первые 500 символов):")
123 print("-" * 50)
124 print(content)
125 print("-" * 50)
126 else:
127 print(f"✗ Не удалось обработать файл")
128
129if __name__ == "__main__":
130 main()