Last active 3 weeks ago

KarelWintersky revised this gist 3 weeks ago. Go to revision

1 file changed, 2 insertions, 1 deletion

fix_mojibake.py

@@ -6,7 +6,8 @@ from pathlib import Path
6 6 """
7 7 Сделано для Димы Андреева, конвертор индексов HTTrack.
8 8
9 - Твой файл на самом деле уже в UTF-8, но содержит испорченные символы (mojibake). Это типичная ситуация, когда UTF-8 текст был прочитан как ISO-8859-1.
9 + Файл на самом деле уже в UTF-8, но содержит испорченные символы (mojibake).
10 + Это типичная ситуация, текст был прочитан как ISO-8859-1, но сохранен в UTF-8 "как есть" без декодирования
10 11 """
11 12
12 13 def fix_mojibake_utf8(input_path, output_path=None):

KarelWintersky revised this gist 3 weeks ago. Go to revision

1 file changed, 5 insertions

fix_mojibake.py

@@ -3,6 +3,11 @@ import sys
3 3 import os
4 4 import argparse
5 5 from pathlib import Path
6 + """
7 + Сделано для Димы Андреева, конвертор индексов HTTrack.
8 +
9 + Твой файл на самом деле уже в UTF-8, но содержит испорченные символы (mojibake). Это типичная ситуация, когда UTF-8 текст был прочитан как ISO-8859-1.
10 + """
6 11
7 12 def fix_mojibake_utf8(input_path, output_path=None):
8 13 """

KarelWintersky revised this gist 3 weeks ago. Go to revision

No changes

KarelWintersky revised this gist 3 weeks ago. Go to revision

No changes

KarelWintersky revised this gist 3 weeks ago. Go to revision

No changes

KarelWintersky revised this gist 3 weeks ago. Go to revision

1 file changed, 125 insertions

fix_mojibake.py(file created)

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