John Doe wrote: Sat 31 Jan, 2026 14:24
Всевозможные
Дубли невозможны в принципе, так как к таблице создается уникальный индекс.
В приведенном примере "Экспортируемые функции" первый раз записано с обычным пробелом, второй раз - с неразрывным.
Страницы-то разные, а вот ключевые слова для поиска дублируются.
У меня не установлен Zeal, но подозреваю что при поиске будет выведена только одна.
Я ещё раз подчеркну, что тут вопрос не к вашим скриптам, и не к Zeal, а к исходным данным.
Что ещё обнаружил: в актуальной справке отсутствуют следующие ключи (ранее существовавшие)
"Правила хорошего тона"
COL_*
OPM_*
Programming Far Manager plugins - Encyclopedia for Developers
SM_*
Авторы
Локализация
Обработка нажатия ESC или "Авторам долгодумающих плагинов посвящается..."
Примеры
Ссылки
Статьи
Упаковщики - ЗА и ПРОТИВ
Пропали они очевидно в результате изменений скрипта их генерирующего.
Возможно они действительно не нужны (в качестве ключей), и достаточно того что всё есть в оглавлении.
John Doe wrote: Sat 31 Jan, 2026 15:18
Страницы-то разные, а вот ключевые слова для поиска дублируются.
У меня не установлен Zeal, но подозреваю что при поиске будет выведена только одна.
Поэкспериментировал с индексом, хранящемся в бинарных потоках #STRINGS, #URLSTR, ...
В принципе почти то же самое выдаёт, что мы извлекаем pluginsr.hhk или pluginsr.hhc.
Но может пригодиться для проверки консистентности данных, поэтому оставлю скрипт здесь.
import struct
import os
import re
import ctypes
def get_codepage_from_lcid(lcid):
"""Try to get the ANSI codepage for a given LCID using Windows API."""
try:
# LOCALE_IDEFAULTANSICODEPAGE = 0x1004
buf = ctypes.create_unicode_buffer(10)
res = ctypes.windll.kernel32.GetLocaleInfoW(lcid, 0x1004, buf, 10)
if res > 0:
return f"cp{buf.value}"
except Exception:
pass
return None
def get_encoding_from_system():
try:
if not os.path.exists('#SYSTEM'):
return None
with open('#SYSTEM', 'rb') as f:
data = f.read(512)
start = data.find(b'HHA Version')
if start != -1:
end = data.find(b'\x00', start)
if end != -1:
lcid_offset = end + 5
if lcid_offset + 4 <= len(data):
lcid = struct.unpack('<I', data[lcid_offset:lcid_offset+4])[0]
print(f"LCID found in #SYSTEM: {hex(lcid)}")
if encoding := get_codepage_from_lcid(lcid):
return encoding
print("Warning: Failed to decode LCID")
except Exception as e:
print(f"Warning: Failed to read LCID from #SYSTEM: {e}")
return None
def get_system_ansi_codepage():
"""Get the current system ANSI code page on Windows or default to cp1251."""
try:
if os.name == 'nt':
acp = ctypes.windll.kernel32.GetACP()
return f"cp{acp}"
except Exception:
pass
return 'cp1251'
def extract_string(f, offset, encoding):
f.seek(offset)
chars = []
while True:
c = f.read(1)
if c == b'\x00' or not c: break
chars.append(c)
return b''.join(chars).decode(encoding, errors='replace')
def extract_url(f_urlstr, offset, encoding):
f_urlstr.seek(offset)
data = f_urlstr.read(1024)
start = 0
while start < len(data) and data[start] == 0: start += 1
end = start
while end < len(data) and data[end] != 0: end += 1
return data[start:end].decode(encoding, errors='replace')
def main():
try:
encoding = get_encoding_from_system()
if not encoding:
encoding = get_system_ansi_codepage()
print(f"LCID not found or unknown, using fallback: {encoding}")
else:
print(f"Using encoding from LCID: {encoding}")
with open('#TOPICS', 'rb') as f_topics, \
open('#STRINGS', 'rb') as f_strings, \
open('#URLTBL', 'rb') as f_urltbl, \
open('#URLSTR', 'rb') as f_urlstr, \
open('index.txt', 'w', encoding='utf-8') as f_out:
file_size = os.path.getsize('#TOPICS')
record_count = file_size // 16
print(f"Found {record_count} topics.")
entries = []
for i in range(record_count):
data = f_topics.read(16)
if len(data) < 16: break
ints = struct.unpack('<4I', data)
string_offset = ints[1]
urltbl_offset = ints[2]
keyword = extract_string(f_strings, string_offset, encoding)
f_urltbl.seek(urltbl_offset)
urltbl_data = f_urltbl.read(12)
if len(urltbl_data) < 12:
url = ""
else:
tbl_ints = struct.unpack('<3I', urltbl_data)
urlstr_offset = tbl_ints[2]
url = extract_url(f_urlstr, urlstr_offset, encoding)
entries.append((keyword, url))
entries.sort(key=lambda x: x[0].lower())
for keyword, url in entries:
f_out.write(f"{keyword} = {url}\n")
print("Extraction complete. Saved to index.txt")
except Exception as e:
print(f"An error occurred: {e}")
if __name__ == "__main__":
main()