Son aktivite 3 weeks ago

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