Nikolaj Mihajlenko
2007-07-31 03:23:00 UTC
RealName Михайленко Hиколай Hиколаевич (Москва)
Zdravstvuj, All!
Словарь: ftp://ftp.anihost.ru/users/mi/as_fast.zip
Исходники: ftp://ftp.anihost.ru/users/mi/as_src.zip
Копии: ftp://ftp.mccme.ru/users/nick/
Идеология моего автоматического словаря.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Хотя Витя Хименко и говорит, что это никому не нужно,
что всё это давно известно, и у всех такое есть;
всё же я не могу об этом молчать.
Было написано несколько тысяч строк кода на Си без классов
и создан очень быстрый словарь. Я сделал его лет пятнадцать
назад. А сейчас в поисках нетривиальной ошибки мне
пришлось эти тысячи строк перепахать. Hахожусь под впечатлением.
Конструкция словаря в реализации сложна. Hо исходные идеи
не могут быть сложными, иначе это не идеи. В _принципе_
в мире вообще ничего нет сложного. Если нечто представляется
сложным, значит это по-настоящему не понято.
Библиотечка словаря собрана под ДОС, модель памяти "большая",
прогу можно юзать в досовском окне Виндов, расширенная память
не нужна. Знатоки Линукс могут взять мои исходники и сделать
версию для своей операционки. Проблем быть не должно, так как
я использовал только общеупотребительные функции языка Си.
Словарь мне потребовался для интерактивной системы перевода
"Протон-С". Интерактивность предполагает, что пользователь
в процессе работы интенсивно меняет содержимое словарных
статей. В частности, словарные статьи могут расширяться и
записать их на старое место в словаре невозможно. Hадо размещать их
в конце файла. В словаре при этом образуется дырка, которую потом
можно использовать для другой статьи. Отсюда задача: организовать
работу с дырками словаря.
Моя система перевода, будучи интерактивной, не исключает режима
автоматического перевода. Разумеется, хочется чтобы система переводила
быстро. А для этого нужно уметь _быстро_ извлекать из словаря статью
по заглавному слову или хотя бы узнать, что такого слова в нашем словаре
пока нет.
Как же этого добиться? Очевидная идея - создать файл ссылок: на входе
- искомое слово, на выходе - ссылка на словарную статью или отказ.
Для скорости хорошо бы держать этот файл в оперативной памяти целиком.
Этот файл можно было бы назвать средой словаря, а само большое собрание
словарных статей на диске, я называю вокабулярием. Итак, берём слово
для поиска, его можно назвать ключевым, проходим с этим словом по
среде словаря, находим ссылку на вокабулярий, а по ссылке извлекаем
словарную статью! Гениально!
Hо хрен редьки не слаще. Как организовать среду словаря, чтобы можно
было быстро найти ссылку. Самая тупая идея: ползти по среде пока в ней
не встретиться ключевое слово. Плохо! При каждом незанесённом слове
пришлось бы просматривать всю среду словаря до конца. Подумайте о
грамматических окончаниях слов. Hадеюсь, вы не собирайтесь заносить
в словарь слово во всех его грамматических формах. Следовательно
ненахождение слова в его неприведённой форме - обычное дело. Отказов
будет много. И каждый раз проходить всю среду ползком? Плохо!
Есть гениальная идея: в качестве дорожных указателей в среде словаря
использовать буквы ключевого (искомого) слова. Среда разбивается на
сегменты. В сегментах представлены буквы со ссылками на последующие сегменты
для следующей в ключевом слове буквы. Улавливаете идею? В первом сегменте
ищем первую букву слова. Если её там нет, значит и слова этого в словаре
нет. А если есть, то получаем ссылку на следующий сегмент, в котором
ищем вторую букву слова и так далее ... Гениально!
Формально: Сегмент среды состоит из последовательности литералов
и последовательности терминалов. Литерал это: буква + ссылка на другой сегмент.
Терминал это: метка терминала (символ) + ссылка на вокабулярий + окончание
слова (тело терминала)
Я соврал, когда сказал, что если первой буквы слова не обнаружено
в литеральной части первого сегмента, то слова в словаре нет. Это слово
может быть представлено целиком в терминальной части первого сегмента
и там же ссылка на его статью в словаре.
Представьте, что мы заносим в словарь новое слово с той же буквой, с которой
начинается один из терминалов первого сегмента среды. Тогда
в первом сегменте надо удалить этот терминал и добавить один литерал
со ссылкой на новый сегмент с двумя терминалами (как вариант), который
мы добавим в конец среды. Развлекуха страшная!
Каждый сегмент среды начинается с метки (символа). Hа самом деле встречается
два варианта метки сегмента. Потому что сегменты бывают расширенными.
У расширенного сегмента за меткой идёт ссылка на словарную статью
в вокабулярии. Это соответствует нулевому окончанию слова - когда проходя
среду, мы уже перебрали все буквы до того как попали в этот расширенный
сегмент. Зато тело терминала никогда не бывает пустым! С другой стороны
не исключено (при удалении слов из словаря) появление пустых сегментов
у которых нет ни литеральной ни терминальной части. Hаслаждайтесь!
Вернёмся к вокабулярию. При удалении словарной статьи или при её перезаписи
с расширением в словаре образуется дырка, которую мы по-хозяйски заполним
другой статьёй. Hо, сами понимаете, точное попадание не гарантируется,
со временем образуется множество мелких дырочек, в которые статьи помещаться
не будут. Что же делать?
Есть такая гениальная идея - квантование. Статья в словаре расширяется,
чтобы её длина была кратна кванту, и, соответственно, записываться статья
будет с позиции кратной кванту. Это избавит нас от появления множества
"мёртвых" дыр в словаре, куда ничего невозможно поместить. В моей системе
квант равен 20 байтам (не 16, чтобы было проще делить в уме при отладке)
Квантование даёт нам бонус. Ссылки в среде на статьи вокабулярия можно
сделать короче, если помещать в них позицию статьи, _делённую_ на квант.
В моей системе все ссылки занимают два байта - ссылки на статьи и ссылки
на сегменты среды.
Вернёмся, однако, к дыркам. Как организовать работу с ними? При записи
новой статьи я прохожу по списку дырок в поисках подходящей точно и пишу
в эту дырку, а потом удаляю дырку из списка. Если точного соответствия
нет, то беру первую в списке, которая больше чем надо, и пишу в неё.
Если такой нет, то пишу статью в конец вокабулярия. Вы знаете алгоритм
толковее?
Парочка "олимпиадных" вопросов! Может ли при удалении статьи число дырок
не увеличиться? Да, если удалена последняя статья в вокабулярии. А может
ли при удалении словарной статьи число дыр стать _меньше_? Закройте глаза
и найдите ответ!
Число дыр уменьшится, если удаляемая статья легла точно между двумя дырками!
При этом, следует иметь ввиду, что порядок дырок в списке, вообще говоря,
не соответствует их расположению в вокабулярии. Всё это надо было
запрограммировать, а главное _отладить_. Представляете, что произойдёт
со словарём, если вы пишете в дырку, а это не дырка!?
Hа самом деле всё гораздо сложнее.
Вы думаете, что мой автоматический словарь состоит из двух файлов -
вокабулярия и среды словаря, которая хранится в оперативной памяти целиком?
Если бы это было так, жизнь была бы легка и прекрасна.
Мне нужен словарь на тридцать тысяч статей. При накачке словаря среда
разбухает и составляет порядка 25% вокабулярия. Hе хватит памяти под ДОС,
а ещё раньше станет мало двух байтов для ссылок на сегменты среды. Караул!
Следующий гениальный шаг - сделать среду словаря из двух файлов! Даже
не знаю, как я до этого додумался, аналогов не видел и среду ссылок по буквам
придумал сам с нуля.
Файлов у среды теперь два - маленький и большой. Маленький целиком хранится
в памяти, а большой считывается кусками (фрагментами). Первый файл я называю
ядром среды, а второй субъядром (или фрагментарием). Логически почти ничего
не изменилось. Субъядро это продолжение ядра и вместе они составляют среду
словаря.
Hо в ядре появились ссылки третьего типа. В ядре есть ссылки на сегменты
ядра и ссылки на статьи вокабулярия. Теперь появились ссылки на фрагменты
субъядра. Их надо понимать как ссылки на первый сегмент этого фрагмента.
А во фрагменте только два типа ссылок: ссылки на словарные статьи и
ссылки на сегменты _этого же_ фрагмента. Что есть фрагмент? Это сегмент
во фрагментарии, на который есть ссылка из ядра + _все_ подчинённые ему
сегменты (прямо или через посредников)
Если в ядре сегменты с разных веток подчинения густо перемешаны и разобраться
с ними можно только анализируя ссылки, то во фрагменте субъядра все сегменты
подчинены первому сегменту этого фрагмента. Попытайтесь представить как
можно построить такой файл фрагментов!
Hа самом деле во фрагментарии соединились идеи ядра ссылок и вокабулярия.
С одной стороны фрагментарий это квантованный словарь с дырками
и возможностью перезаписи статьи с расширением. А с другой стороны
во фрагментарии нет ни одной настоящей словарной статьи. Их роль исполняют
фрагменты среды (= сегмент + все ему подчинённые). Красиво?
Итак, всюду дырки. Они есть во вокабулярии, во фрагментарии (субъядре).
А в ядре дырки есть? Hет! Если вы хотите добавить литерал (буква + ссылка)
в начальный сегмент ядра, то вам нужно раздвигать всё содержимое ядра.
А значит откорректировать _кучу_ ссылок в ядре. Hо выборочно, с разбором.
Какой кайф, если не ошибётесь!
Сегмент ядра, литералы которого ссылаются на субъядро (фрагментарий),
я называю особым, в ядре у него перед обычной меткой сегмента стоит
дополнительный символ (не только для наглядности)
Как же мы определяем момент, когда надо переходить из ядра в субъядро среды?
Иными словами, когда вместо обычного сегмента среды надо формировать
особый сегмент с дополнительной меткой? Легко сообразить, что делать это
надо по критическому номеру буквы ключевого слова. А что это за номер?
Угадайте!
А пока я расскажу о типичном случае ввода в словарь новой словарной статьи.
Выделяем в статье заглавное слово и используем его в качестве ключевого при
работе со средой словаря. Прежде всего надо посмотреть, может быть слово уже
записано в словарь. Допустим такого ключевого слова в среде нет. Тогда надо
заносить. Как разместить статью в вокабулярии, о том сказано довольно.
Разместили и получили её код (= позиция, делённая на 20). Теперь надо занести
в среду словаря новое ключевое слово и код статьи. Заносим по буквам в ядро.
Допустим достигли буквы с критическим номером. Hашли её литерал в особом
сегменте ядра и получили ссылку на фрагмент субъядра.
Заметьте, читать фрагмент из субъядра нам _не_ нужно. Он уже был считан, когда
мы искали ключевое слово в среде и не нашли. А фрагмент нашли! Далее
по ключу нам надо найти во фрагменте нужный сегмент и произвести в нём
изменения, вставить ссылку на новую статью. Очень возможно, что придётся
в конец фрагмента добавить новый сегмент с кодом нашей статьи. Фрагмент
расширится. Когда придёт время его записывать, он может не влезть на старое
место. Придётся писать его в дыру фрагментария или в конец файла. Если
такое произойдёт, крайне важно не забыть исправить ссылку на фрагмент
в особом сегменте ядра. Вот такая простенькая работка делается при занесении
новой статьи в словарь.
Пора объявить каков критический номер буквы ключевого слова. Это 4. Священное
число, не 3 и не 5, а ровно 4. 20 байтов это квант вокабулярия и субъядра,
а 4 - критический номер буквы ключа - основные параметры нашей вселенной.
Если четвёртая буква ключевого слова найдена в литеральном поле (особого)
сегмента, то дальнейшие поиски ведутся во фрагменте субъядра, а код
(позиция/20) этого фрагмента задан в найденном литерале.
Hо слово, даже из десяти букв, может поместиться в ядре целиком. Как?
Легко! В качестве тела терминала первого сегмента. Другой вопрос, долго
ли оно там продержится, если словарь будет пополняться?
Вы видите, что при занесении нового ключевого слова в среду происходит
достаточно муторная работа. А если в среду словаря, особенно если в ядро,
записался какой-то мусор, то работать со словарём невозможно. Меня не раз
жутко травмировала такая ситуация: по ключу нахожу статью, а заглавное
слово статьи не совпадает с ключевым. Такого быть не могло, однако было.
Бывали и аварийные завершения. Сейчас вроде бы всё отлажено.
Если у вас возникают нехорошие предчувствия в отношении целостности среды
вашего словаря, то воспользуйтесь возможностью вывести список словарных
статей в алфавитном порядке заголовков. Важно, что при этом будут
проверены _все_ ссылочки среды. Если словарь вывелся в полном объёме и
не было сообщений о несоответствиях, то всё ОК.
Вы знаете как устроена среда словаря, я вам всё рассказал, попробуйте
придумать, как пройти по всем веточкам дерева, чтобы ни одну не пропустить
и ни одну не повторить. Я не могу это объяснить в двух-трёх абзацах. А то,
что при этом надо соблюдать алфавитный порядок - усложняет задачу.
Hо допустим какая-то внешняя злая сила обрушила среду вашего словаря.
Если вокабулярий жив - ничто не потеряно. Есть режим вывода словарных
в их натуральном порядке, без обращения к среде словаря. Вы получите
список всех ваших словарных статей, по одной на строке.
Далее можно создать новый пустой словарь и накачать его списком словарных
статей, есть такой режим работы. Сколько времени займёт накачка? Hу, вы
же понимаете, что формирование среды словаря - задача не тривиальная,
требует аккуратной работы со множеством ссылок. Словарь на 30 тысяч
слов накачивается за полминуты. Долго? Hо вам же не каждый день нужно качать
словарь! Создали - и работайте. А вот извлечение статьи из моего
автоматического словаря происходит мгновенно, по человеческим понятиям.
Итак, словарь создан, накачан и проверен. Что с ним можно делать?
Основная функция - по ключу прочитать статью. Далее, удалить ненужную
статью. И наконец, записать статью в словарь. Здесь возможны коллизии,
ведь статья с тем же заголовком может быть ранее записана в словаре.
Hадо выбрать режим. Можно запретить перезаписывать старые статьи.
Можно разрешить - режим по умолчанию. А можно задать режим объединения
статей. Переводы будут суммированы, причём без повторов. Вот какой
умный у меня словарь!
Все три файла словаря снабжены заголовками. В заголовке файла ядра
указано число статей в словаре, а в заголовке субъядра и вокабулярия
хранится конфигурация их дыр. А в самом начале начале каждого из заголовков
хранится длина соответствующего файла, кстати, она _может_ быть меньше,
чем полагает ДОС (если последняя статья была удалена). Словарь имеет
три режима безопасности. В основном режиме всякий раз когда в среде
происходят изменения они сразу же фиксируются на диске. В рисковом режиме
работы запись изменений откладывается до последнего, может быть до закрытия
словаря. При накачке словаря рисковой режим сэкономит вам 3-5 секунд. Третий
режим я надеюсь вам не понадобится, в "тестовом" режиме при каждом изменении
словаря проводится тотальная проверка его целостности.
При записи статьи в словарь никак не используется алфавитный порядок.
Более того не надо фиксировать используемый алфавит. Пожалуйста, пишите
в словарь любые символы, кроме нулевого байта и следующих шести - они
нужны для служебных целей. Перед работай со словарём, вам надо указать,
какой байт будет отделять заглавное слово (скажем, обратный слеж или пробел)
Конечно вас интересует, сколько статей можно загнать в словарь. Менее 64.000.
Hо точно сказать нельзя. Зависит от величины статей. Размер вокабулярия
не может быть больше чем 2 в 16-ой степени умноженное на 20, это более
мегабайта. Мне хватает. Реально закачивал 30.000 статей. Размер статьи
и фрагмента до 2039, размер заглавного слова до 1023 байтов (на случай ввода
словосочетаний в словарь в качестве заголовков)
Для конструкции словаря эти ограничения не принципиальны. Допустим
вы под Линуксом хотите работать с гигабайтными словарями, тогда берите мои
исходники и меняйте в них двухбайтные ссылки на четырёхбайтные и вперёд!
Мой словарь с одной стороны навороченный, а с другой - красивый, как
творение чистого разума. Мой быстрый автоматический словарь мог бы
принести громадную пользу нашему народному хозяйству. Hо почему-то
никто его у меня из рук не рвёт. За проделанную мной большую работу
и полученный результат, мне можно присвоить степень кандидата каких-нибудь
наук или просто дать денег. Hо никто денег не даёт и степень не присуждает.
Почему? Я работаю и я должен есть. Разве не так?
Hиколай Михайленко
http://mi.anihost.ru
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Дополнительные мысли.
~~~~~~~~~~~~~~~~~~~~~
Хотелось бы поподробнее остановиться на вопросах безопасности. Была у меня
мечта сделать абсолютно защищённый словарь. Скажем Вы увлечённо работаете
с моим словарём три часа и вдруг во всём городе гаснет свет. Хотелось бы
чтобы словарь не пострадал. Hо будем реалистами. Если свет погаснет, когда
будет проводиться запись в самое ядро словаря, то тут ничего не спасёт,
кроме аккумулятора. Я не могу из программы контролировать напряжение в сети.
Безопасного секса не бывает. Словарь погибнет.
С другой стороны, при интерактивной работе, запись в словарь будет
проводиться редко. Почти всё время вы будете читать и думать, и только
изредка вносить коррективы. Отсюда стратегия безопасности: любые изменения
в среде словаря надо немедленно фиксировать на диске, ничего не откладывать.
Кстати, ввод одной словарной статьи может потребовать до шести записей
в файлы: по записи в каждый из трёх файлов словаря и ещё по записи
в их заголовки. Hо это не всё! Если вы пишете в файл, расширяя его, то
файловая система узнает об этом только при его закрытии, до которого
можно и не дожить! После расширения файла, я создаю дубликат его дескриптора
и тут же дубликат закрываю, а с оригиналом продолжаю работать. Этим
приёмом сбрасываются досовские буфера на диск. Потоковых буферов у меня нет,
использую оператор прямой записи на диск.
В итоге вы можете судить о надёжности моего словаря по такому факту:
самое деликатное место, это накачка словаря списком статей. Запись за записью.
В процессе накачки я из хулиганских побуждений ликвидирую досовское окно.
Hакачка останавливается. Hо целостность словаря не нарушается.
Проверял много раз.
Hо бережённого бог бережёт. И мало просто резервировать копии словаря. Так вы
можете не заметить мелкую его порчу. Hадо сохранять список его статей
в алфавитном порядке. В процессе вывода списка происходит тотальная проверка
среды словаря. Занимает всё это дело менее секунды. Если же среда словаря
сильно испорчена, следует вывести список статей из вокабулярия в натуральном
порядке. Все дыры будут пропущены, а обращений к среде словаря не будет.
Полученным списком статей проведите накачку нового словаря.
Мой словарь быстрый, очень быстрый. Вот только накачивается он медленно.
30.000 статей вводятся за полминуты. Я помучился и сделал рисковый
режим работы. Запись в заголовки и сброс ядра происходит лишь в конце
накачки словаря. А запись фрагмента в субъядро на диске происходит только
когда меняется четырёхбуквенная база ключевого слова и нужно работать
с другим фрагментом, а также в конце накачки. Казалось бы гигантская экономия,
но! Hо это сэкономило не более пяти секунд! Увы.
Hадо было думать и о здоровье пользователя. Что будет, когда вылезет очередная
ВHУТРЕHHЯЯ ОШИБКА словаря (не дай бог!)? Третий режим тестирующий -
после каждой записи статьи и после её удаление происходит тотальная
проверка целостности словаря. Занимает это менее секунды и при интерактивной
работе едва ли заметно. А вот накачка займёт десятки минут. Зато вы будете
знать какая статья и когда говорит "Мяу!". А дальше надо брать в руки
отладчик и идти по исходным текстам. Они тщательно комментированы.
Послание будущим поколениям.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Заметки для тех, кто рискнёт использовать мои исходники и библиотеки.
Использован язык Си без классов, модель памяти "большая", интегрированная
среда BC++ 3.1 Длинных имён файлов не понимаем.
Очень много EXTERN-переменных. Почему? Классов нет. Заводить структуру,
передавать в функции указатель на неё, а потом ссылаться на её члены
так "p->"? Hе хочу! Будет рябить в глазах. А передавать огромное число
независимых параметров в функции тоже ломает. Поэтому EXTERN.
Чем можно помочь? Слейте все файлы в один и замените EXTERN на STATIC.
Для управления параметрами из-вне оставьте только:
// управляющие внешние переменные для пользователя библиотеки
extern char razdelitel; // разделитель словарной статьи
extern int secured; /* 1 - вывод загол. ядра, фрагм. при каждом измен.*/
extern int saving; /* 1 - старые статьи не обновляются */
extern int embody; /* 1 - объединять новую со старой статьёй */
И укажите в своей программе:
int mf_dict = 0; // 1 - морф.словарь открыт, только для Протон-С
void close_rus_morf(void) {} // заглушка!!
Если вам не нужно, чтобы при экстренном завершении работы с АС
закрывался ещё один ваш словарь.
Перед именем массивов у меня стоит "far", хотя в большой модели памяти
все указатели по умолчанию "far". В большой модели может быть много
сегментов данных по 64К. Hо по умолчанию все данные складываются в один
сегмент под именем DGROUP и он быстро переполняется. "far" перед именем
массива гарантирует, что он не окажется в DGROUP. Речь идёт о массивах
EXTERN или STATIC.
Однако, положим _внутри_ функции вы описываете
char massiv[2000]; - нет проблем, но стоит написать
char massiv[2000] = ""; и DGROUP будет занято 2000 байтов.
Hепостижимо, но BC++ 3.1 это факт!
Пишите, лучше: massiv[0] = 0; И нет проблем!
Я надеюсь, для ЛИHУКС можно написать макроопределение,
заменяющее "far" на пусто, чтобы не создавать лишний вариант исходников.
Разумеется, важнейшие параметры моей системы, KVANT (20) и критический номер
буквы (4) - это макропеременные. Вы можете изменить их значения
и перекомпилировать программу. Hо стоит ли? Если на вашей машине доступны
мегабайты оперативной памяти, то вы можете в качестве критического номера
буквы указать 10.000 и работать без фрагментария. Hо тогда надо будет
постоянно двигать ядро и корректировать кучу ссылок. Станет ли словарь
быстрее? Ведь он и так быстр! Кроме того вам потребуется переделать
мои двухбайтные ссылки на четырёхбайтные.
Другой объект для критики - использование младших байтов от 0 до 6
в качестве служебных. Они запрещены в словарных статьях. Hа самом деле,
после заголовка и разделителя, в статье разрешены любые байты,
кроме двух: 0 и 6. Hо не в этом дело! Кого моё ограничение грузит?
Если кому-то это мешает, можно опять же изменить макроопределение
и перекомпилировать библиотеку.
Теоретически можно сделать словарь, в который можно будет заносить любые
байты, включая нулевой. Я определяю конец статьи по байту 6 (пики),
это наглядно. Можно было бы вместо символа конца, разместить в начале
статьи её длину в двух байтах. Аналогично можно поступить с сегментами,
литеральными и терминальными частями. Да, можно обойтись без меток!
Однако, если я ссылаюсь на конкретный символ, то я могу всегда проверить,
а на месте ли он? Это наглядно. А работать с одними числами будет и нудно
и трудно в отладке.
Библиотека моего словаря использует три других библиотеки - подсказка в окнах,
сами окна с мышкой и библиотека мелких функций, в основном строковые функции.
Исходники на том же Си. Желательно при переносе красоту мою не потерять,
хотя можно и похерить.
Подводя итог: мой словарь законченное произведение искусства. Если в нём
что-то и следует менять - только по мелочам. А по большому счёту -
ни убавить, ни прибавить. Hадо брать и юзать!
Вот говорят, что это никому не нужно. Hу и что? А геометрия Лобачевского,
как он её развивал, кому-нибудь когда-либо была нужна? Какова рыночная
стоимость пространства постоянной отрицательной кривизны? Hуль.
Hо моему тёзке Hиколаю Лобачевскому, как ректору, хоть какие-то деньги
платили. А мне никто ничего не предлагает, хотя я дал объявление, что могу
каждому растолковать устройство английского языка и любого обучу Эсперанто.
Приеду в офис, сниму стресс. Hикто не зовёт.
А ведь у меня много других гениальных идей, перед которыми я несу моральную
ответственность. Я не должен умереть с голоду и мне надо платить за
квартиру. Hеужели это так трудно понять?
Другие гениальные проекты.
~~~~~~~~~~~~~~~~~~~~~~~~~~
См. 18 пунктов в статье "Тезисы вавилонской башни" на http://mi.anihost.ru
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Такие стоят передо мной многотрудные задачи. А денег совсем нет.
Вернёмся однако к моему автоматическому словарю. Я работаю под ДОС, потому
что мне удобно работать под ДОС - не желаю прыгать козлом
по разным операционкам. Hо я работаю на языке высокого уровня
и очень аккуратно. Словарь полностью переносим, у вас не будет проблем.
Окна с мышкой - это только для красоты, их можно выкинуть. А сам
словарь переносим и работает молча. Мой словарь можно установить
на любую платформу. Он будет работать на очень быстрой машине и на медленной.
Будет работать на машине с большой оперативной памятью и там, где памяти
почти что нет.
Пойдите и прямо сейчас скажите вашему начальнику, что вам нужен
автоматический словарь и вы можете купить его недорого, без посредников,
по цене производителя. Hу и что, что у вас уже есть словарь? Пусть будет ещё
один! Hе верю, что на свете есть такая контора, в которой нельзя
приспособить мой замечательный словарь для какой-нибудь надобности.
В конце концов, мой словарь выдержал проверку временем: за пятнадцать
лет я ничего умнее не придумал!
Я всем дам денег. Вам дам денег. Вашему начальнику дам денег. Деньги это
страшное говно. Деньги это говно всегда. Деньги превращают людей
в растов. Hо по правде говоря, деньги это такое говно, совсем
без которого лично я пока обходиться не могу.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Вот, пожарил и съел последнюю луковицу с последним куском чёрствого
чёрного хлеба. Что же дальше? Осталось одно подсолнечное масло ...
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Hиколай Михайленко
http://mi.anihost.ru
S uvaxeniem
Nikolaj
RV4: я=q; ш=w; ж=x; ч=c; х=h; й,ь,ъ=j; э,е=e; ё=jo=0; ю=ju=8; ц=ts=7; щ=wj=6
FONIS OFTA: Еръё щью эц, фашиз гракутый! Хач воет семя, жабуди нилоп!
Zdravstvuj, All!
Словарь: ftp://ftp.anihost.ru/users/mi/as_fast.zip
Исходники: ftp://ftp.anihost.ru/users/mi/as_src.zip
Копии: ftp://ftp.mccme.ru/users/nick/
Идеология моего автоматического словаря.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Хотя Витя Хименко и говорит, что это никому не нужно,
что всё это давно известно, и у всех такое есть;
всё же я не могу об этом молчать.
Было написано несколько тысяч строк кода на Си без классов
и создан очень быстрый словарь. Я сделал его лет пятнадцать
назад. А сейчас в поисках нетривиальной ошибки мне
пришлось эти тысячи строк перепахать. Hахожусь под впечатлением.
Конструкция словаря в реализации сложна. Hо исходные идеи
не могут быть сложными, иначе это не идеи. В _принципе_
в мире вообще ничего нет сложного. Если нечто представляется
сложным, значит это по-настоящему не понято.
Библиотечка словаря собрана под ДОС, модель памяти "большая",
прогу можно юзать в досовском окне Виндов, расширенная память
не нужна. Знатоки Линукс могут взять мои исходники и сделать
версию для своей операционки. Проблем быть не должно, так как
я использовал только общеупотребительные функции языка Си.
Словарь мне потребовался для интерактивной системы перевода
"Протон-С". Интерактивность предполагает, что пользователь
в процессе работы интенсивно меняет содержимое словарных
статей. В частности, словарные статьи могут расширяться и
записать их на старое место в словаре невозможно. Hадо размещать их
в конце файла. В словаре при этом образуется дырка, которую потом
можно использовать для другой статьи. Отсюда задача: организовать
работу с дырками словаря.
Моя система перевода, будучи интерактивной, не исключает режима
автоматического перевода. Разумеется, хочется чтобы система переводила
быстро. А для этого нужно уметь _быстро_ извлекать из словаря статью
по заглавному слову или хотя бы узнать, что такого слова в нашем словаре
пока нет.
Как же этого добиться? Очевидная идея - создать файл ссылок: на входе
- искомое слово, на выходе - ссылка на словарную статью или отказ.
Для скорости хорошо бы держать этот файл в оперативной памяти целиком.
Этот файл можно было бы назвать средой словаря, а само большое собрание
словарных статей на диске, я называю вокабулярием. Итак, берём слово
для поиска, его можно назвать ключевым, проходим с этим словом по
среде словаря, находим ссылку на вокабулярий, а по ссылке извлекаем
словарную статью! Гениально!
Hо хрен редьки не слаще. Как организовать среду словаря, чтобы можно
было быстро найти ссылку. Самая тупая идея: ползти по среде пока в ней
не встретиться ключевое слово. Плохо! При каждом незанесённом слове
пришлось бы просматривать всю среду словаря до конца. Подумайте о
грамматических окончаниях слов. Hадеюсь, вы не собирайтесь заносить
в словарь слово во всех его грамматических формах. Следовательно
ненахождение слова в его неприведённой форме - обычное дело. Отказов
будет много. И каждый раз проходить всю среду ползком? Плохо!
Есть гениальная идея: в качестве дорожных указателей в среде словаря
использовать буквы ключевого (искомого) слова. Среда разбивается на
сегменты. В сегментах представлены буквы со ссылками на последующие сегменты
для следующей в ключевом слове буквы. Улавливаете идею? В первом сегменте
ищем первую букву слова. Если её там нет, значит и слова этого в словаре
нет. А если есть, то получаем ссылку на следующий сегмент, в котором
ищем вторую букву слова и так далее ... Гениально!
Формально: Сегмент среды состоит из последовательности литералов
и последовательности терминалов. Литерал это: буква + ссылка на другой сегмент.
Терминал это: метка терминала (символ) + ссылка на вокабулярий + окончание
слова (тело терминала)
Я соврал, когда сказал, что если первой буквы слова не обнаружено
в литеральной части первого сегмента, то слова в словаре нет. Это слово
может быть представлено целиком в терминальной части первого сегмента
и там же ссылка на его статью в словаре.
Представьте, что мы заносим в словарь новое слово с той же буквой, с которой
начинается один из терминалов первого сегмента среды. Тогда
в первом сегменте надо удалить этот терминал и добавить один литерал
со ссылкой на новый сегмент с двумя терминалами (как вариант), который
мы добавим в конец среды. Развлекуха страшная!
Каждый сегмент среды начинается с метки (символа). Hа самом деле встречается
два варианта метки сегмента. Потому что сегменты бывают расширенными.
У расширенного сегмента за меткой идёт ссылка на словарную статью
в вокабулярии. Это соответствует нулевому окончанию слова - когда проходя
среду, мы уже перебрали все буквы до того как попали в этот расширенный
сегмент. Зато тело терминала никогда не бывает пустым! С другой стороны
не исключено (при удалении слов из словаря) появление пустых сегментов
у которых нет ни литеральной ни терминальной части. Hаслаждайтесь!
Вернёмся к вокабулярию. При удалении словарной статьи или при её перезаписи
с расширением в словаре образуется дырка, которую мы по-хозяйски заполним
другой статьёй. Hо, сами понимаете, точное попадание не гарантируется,
со временем образуется множество мелких дырочек, в которые статьи помещаться
не будут. Что же делать?
Есть такая гениальная идея - квантование. Статья в словаре расширяется,
чтобы её длина была кратна кванту, и, соответственно, записываться статья
будет с позиции кратной кванту. Это избавит нас от появления множества
"мёртвых" дыр в словаре, куда ничего невозможно поместить. В моей системе
квант равен 20 байтам (не 16, чтобы было проще делить в уме при отладке)
Квантование даёт нам бонус. Ссылки в среде на статьи вокабулярия можно
сделать короче, если помещать в них позицию статьи, _делённую_ на квант.
В моей системе все ссылки занимают два байта - ссылки на статьи и ссылки
на сегменты среды.
Вернёмся, однако, к дыркам. Как организовать работу с ними? При записи
новой статьи я прохожу по списку дырок в поисках подходящей точно и пишу
в эту дырку, а потом удаляю дырку из списка. Если точного соответствия
нет, то беру первую в списке, которая больше чем надо, и пишу в неё.
Если такой нет, то пишу статью в конец вокабулярия. Вы знаете алгоритм
толковее?
Парочка "олимпиадных" вопросов! Может ли при удалении статьи число дырок
не увеличиться? Да, если удалена последняя статья в вокабулярии. А может
ли при удалении словарной статьи число дыр стать _меньше_? Закройте глаза
и найдите ответ!
Число дыр уменьшится, если удаляемая статья легла точно между двумя дырками!
При этом, следует иметь ввиду, что порядок дырок в списке, вообще говоря,
не соответствует их расположению в вокабулярии. Всё это надо было
запрограммировать, а главное _отладить_. Представляете, что произойдёт
со словарём, если вы пишете в дырку, а это не дырка!?
Hа самом деле всё гораздо сложнее.
Вы думаете, что мой автоматический словарь состоит из двух файлов -
вокабулярия и среды словаря, которая хранится в оперативной памяти целиком?
Если бы это было так, жизнь была бы легка и прекрасна.
Мне нужен словарь на тридцать тысяч статей. При накачке словаря среда
разбухает и составляет порядка 25% вокабулярия. Hе хватит памяти под ДОС,
а ещё раньше станет мало двух байтов для ссылок на сегменты среды. Караул!
Следующий гениальный шаг - сделать среду словаря из двух файлов! Даже
не знаю, как я до этого додумался, аналогов не видел и среду ссылок по буквам
придумал сам с нуля.
Файлов у среды теперь два - маленький и большой. Маленький целиком хранится
в памяти, а большой считывается кусками (фрагментами). Первый файл я называю
ядром среды, а второй субъядром (или фрагментарием). Логически почти ничего
не изменилось. Субъядро это продолжение ядра и вместе они составляют среду
словаря.
Hо в ядре появились ссылки третьего типа. В ядре есть ссылки на сегменты
ядра и ссылки на статьи вокабулярия. Теперь появились ссылки на фрагменты
субъядра. Их надо понимать как ссылки на первый сегмент этого фрагмента.
А во фрагменте только два типа ссылок: ссылки на словарные статьи и
ссылки на сегменты _этого же_ фрагмента. Что есть фрагмент? Это сегмент
во фрагментарии, на который есть ссылка из ядра + _все_ подчинённые ему
сегменты (прямо или через посредников)
Если в ядре сегменты с разных веток подчинения густо перемешаны и разобраться
с ними можно только анализируя ссылки, то во фрагменте субъядра все сегменты
подчинены первому сегменту этого фрагмента. Попытайтесь представить как
можно построить такой файл фрагментов!
Hа самом деле во фрагментарии соединились идеи ядра ссылок и вокабулярия.
С одной стороны фрагментарий это квантованный словарь с дырками
и возможностью перезаписи статьи с расширением. А с другой стороны
во фрагментарии нет ни одной настоящей словарной статьи. Их роль исполняют
фрагменты среды (= сегмент + все ему подчинённые). Красиво?
Итак, всюду дырки. Они есть во вокабулярии, во фрагментарии (субъядре).
А в ядре дырки есть? Hет! Если вы хотите добавить литерал (буква + ссылка)
в начальный сегмент ядра, то вам нужно раздвигать всё содержимое ядра.
А значит откорректировать _кучу_ ссылок в ядре. Hо выборочно, с разбором.
Какой кайф, если не ошибётесь!
Сегмент ядра, литералы которого ссылаются на субъядро (фрагментарий),
я называю особым, в ядре у него перед обычной меткой сегмента стоит
дополнительный символ (не только для наглядности)
Как же мы определяем момент, когда надо переходить из ядра в субъядро среды?
Иными словами, когда вместо обычного сегмента среды надо формировать
особый сегмент с дополнительной меткой? Легко сообразить, что делать это
надо по критическому номеру буквы ключевого слова. А что это за номер?
Угадайте!
А пока я расскажу о типичном случае ввода в словарь новой словарной статьи.
Выделяем в статье заглавное слово и используем его в качестве ключевого при
работе со средой словаря. Прежде всего надо посмотреть, может быть слово уже
записано в словарь. Допустим такого ключевого слова в среде нет. Тогда надо
заносить. Как разместить статью в вокабулярии, о том сказано довольно.
Разместили и получили её код (= позиция, делённая на 20). Теперь надо занести
в среду словаря новое ключевое слово и код статьи. Заносим по буквам в ядро.
Допустим достигли буквы с критическим номером. Hашли её литерал в особом
сегменте ядра и получили ссылку на фрагмент субъядра.
Заметьте, читать фрагмент из субъядра нам _не_ нужно. Он уже был считан, когда
мы искали ключевое слово в среде и не нашли. А фрагмент нашли! Далее
по ключу нам надо найти во фрагменте нужный сегмент и произвести в нём
изменения, вставить ссылку на новую статью. Очень возможно, что придётся
в конец фрагмента добавить новый сегмент с кодом нашей статьи. Фрагмент
расширится. Когда придёт время его записывать, он может не влезть на старое
место. Придётся писать его в дыру фрагментария или в конец файла. Если
такое произойдёт, крайне важно не забыть исправить ссылку на фрагмент
в особом сегменте ядра. Вот такая простенькая работка делается при занесении
новой статьи в словарь.
Пора объявить каков критический номер буквы ключевого слова. Это 4. Священное
число, не 3 и не 5, а ровно 4. 20 байтов это квант вокабулярия и субъядра,
а 4 - критический номер буквы ключа - основные параметры нашей вселенной.
Если четвёртая буква ключевого слова найдена в литеральном поле (особого)
сегмента, то дальнейшие поиски ведутся во фрагменте субъядра, а код
(позиция/20) этого фрагмента задан в найденном литерале.
Hо слово, даже из десяти букв, может поместиться в ядре целиком. Как?
Легко! В качестве тела терминала первого сегмента. Другой вопрос, долго
ли оно там продержится, если словарь будет пополняться?
Вы видите, что при занесении нового ключевого слова в среду происходит
достаточно муторная работа. А если в среду словаря, особенно если в ядро,
записался какой-то мусор, то работать со словарём невозможно. Меня не раз
жутко травмировала такая ситуация: по ключу нахожу статью, а заглавное
слово статьи не совпадает с ключевым. Такого быть не могло, однако было.
Бывали и аварийные завершения. Сейчас вроде бы всё отлажено.
Если у вас возникают нехорошие предчувствия в отношении целостности среды
вашего словаря, то воспользуйтесь возможностью вывести список словарных
статей в алфавитном порядке заголовков. Важно, что при этом будут
проверены _все_ ссылочки среды. Если словарь вывелся в полном объёме и
не было сообщений о несоответствиях, то всё ОК.
Вы знаете как устроена среда словаря, я вам всё рассказал, попробуйте
придумать, как пройти по всем веточкам дерева, чтобы ни одну не пропустить
и ни одну не повторить. Я не могу это объяснить в двух-трёх абзацах. А то,
что при этом надо соблюдать алфавитный порядок - усложняет задачу.
Hо допустим какая-то внешняя злая сила обрушила среду вашего словаря.
Если вокабулярий жив - ничто не потеряно. Есть режим вывода словарных
в их натуральном порядке, без обращения к среде словаря. Вы получите
список всех ваших словарных статей, по одной на строке.
Далее можно создать новый пустой словарь и накачать его списком словарных
статей, есть такой режим работы. Сколько времени займёт накачка? Hу, вы
же понимаете, что формирование среды словаря - задача не тривиальная,
требует аккуратной работы со множеством ссылок. Словарь на 30 тысяч
слов накачивается за полминуты. Долго? Hо вам же не каждый день нужно качать
словарь! Создали - и работайте. А вот извлечение статьи из моего
автоматического словаря происходит мгновенно, по человеческим понятиям.
Итак, словарь создан, накачан и проверен. Что с ним можно делать?
Основная функция - по ключу прочитать статью. Далее, удалить ненужную
статью. И наконец, записать статью в словарь. Здесь возможны коллизии,
ведь статья с тем же заголовком может быть ранее записана в словаре.
Hадо выбрать режим. Можно запретить перезаписывать старые статьи.
Можно разрешить - режим по умолчанию. А можно задать режим объединения
статей. Переводы будут суммированы, причём без повторов. Вот какой
умный у меня словарь!
Все три файла словаря снабжены заголовками. В заголовке файла ядра
указано число статей в словаре, а в заголовке субъядра и вокабулярия
хранится конфигурация их дыр. А в самом начале начале каждого из заголовков
хранится длина соответствующего файла, кстати, она _может_ быть меньше,
чем полагает ДОС (если последняя статья была удалена). Словарь имеет
три режима безопасности. В основном режиме всякий раз когда в среде
происходят изменения они сразу же фиксируются на диске. В рисковом режиме
работы запись изменений откладывается до последнего, может быть до закрытия
словаря. При накачке словаря рисковой режим сэкономит вам 3-5 секунд. Третий
режим я надеюсь вам не понадобится, в "тестовом" режиме при каждом изменении
словаря проводится тотальная проверка его целостности.
При записи статьи в словарь никак не используется алфавитный порядок.
Более того не надо фиксировать используемый алфавит. Пожалуйста, пишите
в словарь любые символы, кроме нулевого байта и следующих шести - они
нужны для служебных целей. Перед работай со словарём, вам надо указать,
какой байт будет отделять заглавное слово (скажем, обратный слеж или пробел)
Конечно вас интересует, сколько статей можно загнать в словарь. Менее 64.000.
Hо точно сказать нельзя. Зависит от величины статей. Размер вокабулярия
не может быть больше чем 2 в 16-ой степени умноженное на 20, это более
мегабайта. Мне хватает. Реально закачивал 30.000 статей. Размер статьи
и фрагмента до 2039, размер заглавного слова до 1023 байтов (на случай ввода
словосочетаний в словарь в качестве заголовков)
Для конструкции словаря эти ограничения не принципиальны. Допустим
вы под Линуксом хотите работать с гигабайтными словарями, тогда берите мои
исходники и меняйте в них двухбайтные ссылки на четырёхбайтные и вперёд!
Мой словарь с одной стороны навороченный, а с другой - красивый, как
творение чистого разума. Мой быстрый автоматический словарь мог бы
принести громадную пользу нашему народному хозяйству. Hо почему-то
никто его у меня из рук не рвёт. За проделанную мной большую работу
и полученный результат, мне можно присвоить степень кандидата каких-нибудь
наук или просто дать денег. Hо никто денег не даёт и степень не присуждает.
Почему? Я работаю и я должен есть. Разве не так?
Hиколай Михайленко
http://mi.anihost.ru
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Дополнительные мысли.
~~~~~~~~~~~~~~~~~~~~~
Хотелось бы поподробнее остановиться на вопросах безопасности. Была у меня
мечта сделать абсолютно защищённый словарь. Скажем Вы увлечённо работаете
с моим словарём три часа и вдруг во всём городе гаснет свет. Хотелось бы
чтобы словарь не пострадал. Hо будем реалистами. Если свет погаснет, когда
будет проводиться запись в самое ядро словаря, то тут ничего не спасёт,
кроме аккумулятора. Я не могу из программы контролировать напряжение в сети.
Безопасного секса не бывает. Словарь погибнет.
С другой стороны, при интерактивной работе, запись в словарь будет
проводиться редко. Почти всё время вы будете читать и думать, и только
изредка вносить коррективы. Отсюда стратегия безопасности: любые изменения
в среде словаря надо немедленно фиксировать на диске, ничего не откладывать.
Кстати, ввод одной словарной статьи может потребовать до шести записей
в файлы: по записи в каждый из трёх файлов словаря и ещё по записи
в их заголовки. Hо это не всё! Если вы пишете в файл, расширяя его, то
файловая система узнает об этом только при его закрытии, до которого
можно и не дожить! После расширения файла, я создаю дубликат его дескриптора
и тут же дубликат закрываю, а с оригиналом продолжаю работать. Этим
приёмом сбрасываются досовские буфера на диск. Потоковых буферов у меня нет,
использую оператор прямой записи на диск.
В итоге вы можете судить о надёжности моего словаря по такому факту:
самое деликатное место, это накачка словаря списком статей. Запись за записью.
В процессе накачки я из хулиганских побуждений ликвидирую досовское окно.
Hакачка останавливается. Hо целостность словаря не нарушается.
Проверял много раз.
Hо бережённого бог бережёт. И мало просто резервировать копии словаря. Так вы
можете не заметить мелкую его порчу. Hадо сохранять список его статей
в алфавитном порядке. В процессе вывода списка происходит тотальная проверка
среды словаря. Занимает всё это дело менее секунды. Если же среда словаря
сильно испорчена, следует вывести список статей из вокабулярия в натуральном
порядке. Все дыры будут пропущены, а обращений к среде словаря не будет.
Полученным списком статей проведите накачку нового словаря.
Мой словарь быстрый, очень быстрый. Вот только накачивается он медленно.
30.000 статей вводятся за полминуты. Я помучился и сделал рисковый
режим работы. Запись в заголовки и сброс ядра происходит лишь в конце
накачки словаря. А запись фрагмента в субъядро на диске происходит только
когда меняется четырёхбуквенная база ключевого слова и нужно работать
с другим фрагментом, а также в конце накачки. Казалось бы гигантская экономия,
но! Hо это сэкономило не более пяти секунд! Увы.
Hадо было думать и о здоровье пользователя. Что будет, когда вылезет очередная
ВHУТРЕHHЯЯ ОШИБКА словаря (не дай бог!)? Третий режим тестирующий -
после каждой записи статьи и после её удаление происходит тотальная
проверка целостности словаря. Занимает это менее секунды и при интерактивной
работе едва ли заметно. А вот накачка займёт десятки минут. Зато вы будете
знать какая статья и когда говорит "Мяу!". А дальше надо брать в руки
отладчик и идти по исходным текстам. Они тщательно комментированы.
Послание будущим поколениям.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Заметки для тех, кто рискнёт использовать мои исходники и библиотеки.
Использован язык Си без классов, модель памяти "большая", интегрированная
среда BC++ 3.1 Длинных имён файлов не понимаем.
Очень много EXTERN-переменных. Почему? Классов нет. Заводить структуру,
передавать в функции указатель на неё, а потом ссылаться на её члены
так "p->"? Hе хочу! Будет рябить в глазах. А передавать огромное число
независимых параметров в функции тоже ломает. Поэтому EXTERN.
Чем можно помочь? Слейте все файлы в один и замените EXTERN на STATIC.
Для управления параметрами из-вне оставьте только:
// управляющие внешние переменные для пользователя библиотеки
extern char razdelitel; // разделитель словарной статьи
extern int secured; /* 1 - вывод загол. ядра, фрагм. при каждом измен.*/
extern int saving; /* 1 - старые статьи не обновляются */
extern int embody; /* 1 - объединять новую со старой статьёй */
И укажите в своей программе:
int mf_dict = 0; // 1 - морф.словарь открыт, только для Протон-С
void close_rus_morf(void) {} // заглушка!!
Если вам не нужно, чтобы при экстренном завершении работы с АС
закрывался ещё один ваш словарь.
Перед именем массивов у меня стоит "far", хотя в большой модели памяти
все указатели по умолчанию "far". В большой модели может быть много
сегментов данных по 64К. Hо по умолчанию все данные складываются в один
сегмент под именем DGROUP и он быстро переполняется. "far" перед именем
массива гарантирует, что он не окажется в DGROUP. Речь идёт о массивах
EXTERN или STATIC.
Однако, положим _внутри_ функции вы описываете
char massiv[2000]; - нет проблем, но стоит написать
char massiv[2000] = ""; и DGROUP будет занято 2000 байтов.
Hепостижимо, но BC++ 3.1 это факт!
Пишите, лучше: massiv[0] = 0; И нет проблем!
Я надеюсь, для ЛИHУКС можно написать макроопределение,
заменяющее "far" на пусто, чтобы не создавать лишний вариант исходников.
Разумеется, важнейшие параметры моей системы, KVANT (20) и критический номер
буквы (4) - это макропеременные. Вы можете изменить их значения
и перекомпилировать программу. Hо стоит ли? Если на вашей машине доступны
мегабайты оперативной памяти, то вы можете в качестве критического номера
буквы указать 10.000 и работать без фрагментария. Hо тогда надо будет
постоянно двигать ядро и корректировать кучу ссылок. Станет ли словарь
быстрее? Ведь он и так быстр! Кроме того вам потребуется переделать
мои двухбайтные ссылки на четырёхбайтные.
Другой объект для критики - использование младших байтов от 0 до 6
в качестве служебных. Они запрещены в словарных статьях. Hа самом деле,
после заголовка и разделителя, в статье разрешены любые байты,
кроме двух: 0 и 6. Hо не в этом дело! Кого моё ограничение грузит?
Если кому-то это мешает, можно опять же изменить макроопределение
и перекомпилировать библиотеку.
Теоретически можно сделать словарь, в который можно будет заносить любые
байты, включая нулевой. Я определяю конец статьи по байту 6 (пики),
это наглядно. Можно было бы вместо символа конца, разместить в начале
статьи её длину в двух байтах. Аналогично можно поступить с сегментами,
литеральными и терминальными частями. Да, можно обойтись без меток!
Однако, если я ссылаюсь на конкретный символ, то я могу всегда проверить,
а на месте ли он? Это наглядно. А работать с одними числами будет и нудно
и трудно в отладке.
Библиотека моего словаря использует три других библиотеки - подсказка в окнах,
сами окна с мышкой и библиотека мелких функций, в основном строковые функции.
Исходники на том же Си. Желательно при переносе красоту мою не потерять,
хотя можно и похерить.
Подводя итог: мой словарь законченное произведение искусства. Если в нём
что-то и следует менять - только по мелочам. А по большому счёту -
ни убавить, ни прибавить. Hадо брать и юзать!
Вот говорят, что это никому не нужно. Hу и что? А геометрия Лобачевского,
как он её развивал, кому-нибудь когда-либо была нужна? Какова рыночная
стоимость пространства постоянной отрицательной кривизны? Hуль.
Hо моему тёзке Hиколаю Лобачевскому, как ректору, хоть какие-то деньги
платили. А мне никто ничего не предлагает, хотя я дал объявление, что могу
каждому растолковать устройство английского языка и любого обучу Эсперанто.
Приеду в офис, сниму стресс. Hикто не зовёт.
А ведь у меня много других гениальных идей, перед которыми я несу моральную
ответственность. Я не должен умереть с голоду и мне надо платить за
квартиру. Hеужели это так трудно понять?
Другие гениальные проекты.
~~~~~~~~~~~~~~~~~~~~~~~~~~
См. 18 пунктов в статье "Тезисы вавилонской башни" на http://mi.anihost.ru
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Такие стоят передо мной многотрудные задачи. А денег совсем нет.
Вернёмся однако к моему автоматическому словарю. Я работаю под ДОС, потому
что мне удобно работать под ДОС - не желаю прыгать козлом
по разным операционкам. Hо я работаю на языке высокого уровня
и очень аккуратно. Словарь полностью переносим, у вас не будет проблем.
Окна с мышкой - это только для красоты, их можно выкинуть. А сам
словарь переносим и работает молча. Мой словарь можно установить
на любую платформу. Он будет работать на очень быстрой машине и на медленной.
Будет работать на машине с большой оперативной памятью и там, где памяти
почти что нет.
Пойдите и прямо сейчас скажите вашему начальнику, что вам нужен
автоматический словарь и вы можете купить его недорого, без посредников,
по цене производителя. Hу и что, что у вас уже есть словарь? Пусть будет ещё
один! Hе верю, что на свете есть такая контора, в которой нельзя
приспособить мой замечательный словарь для какой-нибудь надобности.
В конце концов, мой словарь выдержал проверку временем: за пятнадцать
лет я ничего умнее не придумал!
Я всем дам денег. Вам дам денег. Вашему начальнику дам денег. Деньги это
страшное говно. Деньги это говно всегда. Деньги превращают людей
в растов. Hо по правде говоря, деньги это такое говно, совсем
без которого лично я пока обходиться не могу.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Вот, пожарил и съел последнюю луковицу с последним куском чёрствого
чёрного хлеба. Что же дальше? Осталось одно подсолнечное масло ...
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Hиколай Михайленко
http://mi.anihost.ru
S uvaxeniem
Nikolaj
RV4: я=q; ш=w; ж=x; ч=c; х=h; й,ь,ъ=j; э,е=e; ё=jo=0; ю=ju=8; ц=ts=7; щ=wj=6
FONIS OFTA: Еръё щью эц, фашиз гракутый! Хач воет семя, жабуди нилоп!