|
|
ГОВОРЯЩИЙ ТЕКСТОВЫЙ РЕДАКТОР "DEMAGOG" |
|
| SPEAKING TEXT EDITOR WITH MULTILINGUAL INTERFACE | ||
| 3-е место в конкурсе Soft.Mail.ru "Самые популярные программы 2009 года" в номинации "Текст" |
![]() |
|
Новое в версии 4.17.228 Небольшие поправки и улучшения. |
Введение
| Но этот меч, который я даю вам в руки, |
| есть лучший из всех мечей, что я раньше сделал. |
| Для этой цели удача посетила меня. |
| Я сделал это из философских соображений... |
| Оружейник Хаттори Хансо |
Demagog - это бесплатная программа, в качестве бонуса прилагается исходный текст версии 3.05.134. (Дальнейшие версии ничего в себе сверхъестественно-нового не несут, изменения касались, в основном, лишь деталей интерфейса: "многооконность", "многословарность" и "многоязычность" - это не принципиально). Ссылка на Demagog'a имеется на портале Soft@Mail.ru: Лучшие программы со всего мира, но новые версии надо скачивать только с этой моей странички:
| Demagog.zip | Дистрибутив программы: Demagog.exe; Demagog-Russian.chm, Demagog-Ukrainian.chm, Demagog-English.chm (справки); lame.exe (аудио-конвертер wav=>mp3), oggenc2.exe (аудио-конвертер wav=>ogg), ~orfo~ (орфотаблица для русского языка); а также упомянутый выше исходный текст. |
| DemagogCHM.zip | Отдельно справки на русском, украинском и английском. Их редакция может быть такой же или более новой, чем в дистрибутиве. |
| orfo.zip | Значительно более полный вариант русской орфотаблицы. В отличие от поставляемой с дистрибутивом, эта орфотаблица содержит и варианты с буквой "ё". |
| DemagogSimpleDIC.zip | Словарь для движка Elan Nikolai: DemagogSimple.dic (около 4000 правил). Никаких гарантий, что он не содержат ошибочных или излишних правил, не дается. |
| Lat2Cyr.zip | Словарь "транслитер" для преобразования латиницы в кириллицу. |
| Bilingva.zip | Словарик для чтения двуязычного русско-английского текста! Он вставляет в текст теги смены голосового движка. И, будучи подключенным вместе с каким-либо другим REX-словарем, делает замены в тексте в последнюю очередь. Не зря у него такое алфавитно-последнее имя: Я_Билингва_SAPI5.rex. |
Пользователи вправе модифицировать прилагаемый исходный код и использовать перекомпилированные версии по своему усмотрению.
Фрагменты исходного текста Demagog'a были использованы разработчиками погодного робота Meteonova, созданного под руководством кандидата географических наук Александра Королькова.
Многие слышали об их существовании,
а кое-кто даже ими пользуется.
Программы-читалки текстов, берегущие наши глаза. "Говорилка", "Балаболка",
"MP3book"..., и
другие, не столь известные. Считается, что создать нечто подобное - это высший
программистский пилотаж
.
Здесь я кратко опишу упражнение на языке Delphi, дающее
вполне удовлетворительный результат.
Тестировалось под ОС Windows 98, NT, 2000, XP, Vista, 7. Вот...

С версии 4.14.176 программа обзавелась многоязычным интерфейсом:

Итак, начнем с начала. Задача "синтеза речи", т.е. превращение электронного текста в звук давно решена средствами Windows. В Win 98, NT, 2000 установлен т.н. "менеджер голосовых функций" - Speech API версии 4.0. Сокращенно: SAPI4. В Win XP, Vista - SAPI5.1. Эти голосовые системы абсолютно не совместимы, но друг другу не мешают и могут сосуществовать на одном компьютере. Версии Demagog'a вплоть до 1.08.042 поддерживали только SAPI4. Если на Вашем компьютере не установлена SAPI4, то взять ее на халяву можно на сайте Microsoft http://activex.microsoft.com/activex/controls/sapi/spchapi.exe (824 Kb) или здесь.
Далее. Чтобы компьютер заговорил, на нем должна быть установлена хоть одна Text To Speech Engine. В переводе на русский: "голосовой движок". Бесплатных голосов для SAPI4 можно, опять же даром, набрать у Майкрософта. Дикция у них, правда, не ахти. А самый лучший на настоящее время голосовой движок под SAPI4 - это Nicolai от фирмы Elan - самая последняя, на 16 кгц, версия известного движка от Digalo. Размер файла Acapela-Elan-TTS-SpeechCube-5.1-RUS-Nicolai_MmE255.msi - примерно 11 Mb. При установке не требует регистрации.
Остается соорудить программную оболочку, для распознавания имеющихся на компьютере голосовых движков, загрузки текстового файла и передачи его выбранному движку для чтения вслух!
Demagog использует низкоуровневый (COM) интерфейс SAPI4. Очень ясно (с примерами и без лишних деталей) необходимые функции SAPI4 описаны в статьях Брайана Лонга (для тех, кто читает на английском) и в книге Дениса Буторина "MS Agent и Speech API для Delphi". Первую половину книжки, про MS Agent'a (создание мультяшных "помощников") смело пропускаем. Дальше читаем внимательно. Поэкспериментируйте с демо-проектами с прилагаемого к книге CD. Стараться понять до конца, как это работает, не нужно, главное - усвоить последовательность, в какой должны объявляться TTS-интерфейсы. Для хранения текста используется компонент RichEdit. Кнопки добавляются "по вкусу". Я использовал компоненты ActionList и ImageList для централизованного построения графического интерфейса.
Действовал в духе "минимализма". Demagog открывает только т.н. плоские тексты - лишь они пригодны для голосовых движков. Кодировка по умолчанию - Windows. Впрочем, Demagog понимает кодировку DOS (из уважения к DOS) и KOI8-R (из уважения к Максиму Мошкову). А файлы следующих форматов: htm, html, shtml, fb2, rtf, doc, docx - автоматически преобразуются в плоский текст, но уже в новом файле, с расширением .txt. Всего может быть одновременно открыто до 10 файлов. (А зачем больше?!) Кроме стандартных функций текстового редактора добавлено удаление знаков переноса в конце строк и форматирование литературного текста.
Demagog поддерживает словари корректировки произношения популярного формата DIC, а также словари формата REX на основе регулярных выражений.
Вместо чтения вслух Demagog может ускоренно записать аудио-файл типа WAV, MP3 или OGG, звук при этом не слышен. Для конвертирования WAV Demagog вызывает внешние программы lame.exe или oggenc2.exe; они включены в установочный комплект, поскольку бесплатные и свободно распространяемые.
Редко,
но бывает (я таки наблюдал однажды подобный казус), когда т.н. "эффект
прозрачности" в интерфейсе Aero Windows 7 настолько
жрет системные ресурсы, что внешний аудио-конвертер не запускается. Есть 3 различных
решения: 1) свернуть застопорившего
Demagog'a в значок и процесс
пойдет; 2) заранее выбрать в настройках Windows 7 любую не-Aero
тему; 3) в свойствах значка Demagog'a на
Рабочем столе на вкладке "Совместимость" поставить галочку "Отключить композицию
рабочего стола".
Можно также улучшить стиль чтения вставкой небольших пауз на пустых строках и между абзацами, а также выделяя прямую речь персонажей громкостью и тембром голоса - для этого предусмотрены 9 специальных "ключевых слов", которые добавляются в словарь. Пример чтения.
Начиная с версии 3.01.117 поддерживается импорт рисунков из открываемых документов MS Word (doc, docx, rtf) и Fiction Book (fb2).
Проект с поддержкой одного только SAPI4 обошелся без использования сторонних компонентов и прекрасно скомпилировался на Turbo Delphi 2006 Explorer.
С распространением Windows XP разработчики говорящих программ отложили в сторону книгу Дениса Буторина, и взялись за статьи Брайана Лонга, в которых рассказано, как заставить Delphi понимать SAPI5.
Для этого необходим пакет SpeechSDK51.exe (68Mb), который можно скачать с официального сайта Microsoft. После его установки запускаем Delphi.
Для Delphi 7 выполняем "Project - Import Type Library". В открывшемся диалоге находим "Microsoft Speech Object Library", номер версии может стоять 5.0 или 5.1 - без разницы. По умолчанию будет предложено поместить компоненты на страницу палитры компонентов AciveX. Вводим свое название, например: SAPI. Запоминаем каталог (или вводим свой) куда поместить юнит. Убеждаемся, что галочка "Generate Component Wrappers" включена. "Install - Into New Package".
Для Delphi 2007 порядок немного другой. "Componrnt - Import Component". "Import a Type Library". В открывшемся диалоге находим "Microsoft Speech Object Library". Назначаем имя страницы на палитре компонентов: SAPI. Убеждаемся, что стоит галка на Generate Component Wrappers". Дальше будет единственный вариант "Create Unit", его имя будет SpeechLib_TLB.pas. Не забываем, куда он лег! В окне Project Manager на пункте "No project group" правой клавишей мыши открываем меню и выбираем "Add New Project...", далее: "Package". Появится вкладка "Package1.bpl",c присоединенными папками. На папке "Contains" правой клавишей раскрываем меню, "Add...". Указываем на созданный юнит. Снова правой правой клавишей на "Package1.bpl", "Install".
Появится сообщение с перечнем установленных компонентов. OK. Если затем мы создадим новую форму, то на палитре компонентов увидим, среди прочих, страницу "SAPI" с 19-ю новыми компонентами!
Продолжим читать дальше статью Б.Лонга - теперь приведенные в ней примеры будут успешно компилироваться.
Для SAPI5 имеются русскоязычные голосовые движки: Катерина-2 от Next Up (49Mb), Alyona 2.210 от Acapela Group (170Mb), Olga от Loquendo (85Mb). Расскажу подробнее о каждой дамочке. Испытания проводились на демонстрационной SAPI5-совместимой читалке, написанной Брайаном Лонгом.

Катерина-2. Первая версия голоса Katerina до сих пор гуляет по Сети и скачивать ее очень не советую. Она изначально говорит тягуче-медленным голосом законченной наркоманки; дистрибутив содержит в придачу "лекарство", приводящее Катю в чувство. Кроме того, движок плохо исполняет команду SAPI5: SpVoice.Skip('Sentence',MaxInt) - в результате после останова чтения длинного (за сотню килобайт) текста, Катюня впадала в ступор минуты на две. Катерина-2 свободна от указанных недостатков, а также делает меньше ошибок в ударениях.
Алена 2.210. Предыдущая версия движка прославилась тем, что не работала под низкоуровневым интерфейсом SAPI4, выдавая фатальную ошибку "Floating point division by zero". Под SAPI5 перед началом чтения длинного текста делает долгую паузу. Кроме того, полностью игнорирует команду SpVoice.Skip().
Ольга. Под SAPI5 выдержала экзамен без замечаний. (Под SAPI4 отсутствует слежение за чтением и регулировка скорости чтения. Нормальный темп чтения будет, если скорость выставить в 0). Из женских русских голосов под SAPI5 - этот самый лучший. Хотя интонации у нее - слегка прибалтийские.
Николай Еланыч. Наш старый друг везде прекрасно себя чувствует, хочешь под SAPI5, хочешь под SAPI4. Конкурентов среди русских мужских голосов пока нет. Разные каменья в него бросали (хрипат, монотонен, и т.п.), а вот моя знакомая, впервые услышав его чтение, воскликнула: "Какой приятный голос!" Может потому, что ритмика фразы у него - русская. (Вряд ли это случайно, ибо в основу движка положены разработки Санкт-Петербургской лаборатории фонетики).
Образцы звучания упомянутых голосов приведены ниже. Читался отрывок из романа А.Дюма "Граф Монте-Кристо".
| Голос | Аудиофайл | Применялись ли словарные замены |
| Acapela Elan Nikolai 16 kHz | MK-Nikolai.mp3 | Да ($Дантес=Дантэ<с | *смотрите,=смотри<те, | замке=за<мке | *гляды*=гля<ды | поднял*=подня<л | хозяин*=хозя<ин | вот=во<т | *нибудь=нибу<дьь) |
| Next Up Katerina-2 | MK-Katerina2.mp3 | Нет |
| Acapela Alyona 2.210 | MK-Alyona.mp3 | Да ($Лево=лево | смотрите=сматрите | губам=губ'ам) |
| Loquendo Olga | MK-Olga.mp3 | Да ($Дантес=Дант^ес | смотрите=смотр^ите | тартан*=тарт^ан | выстрел*=в^ыстрел) |
Теперь начинаем творить собственную читалку под SAPI5. Правда вы (а также я) - не первые. Нас, братцы мои, опередили! Гляньте сюда. Двуязычный синтезатор речи EXO Игоря Паламара, на основе статьи Брайана Лонга. Прилагаются исходные тексты программы и сама статья. Кстати, полезное упражнение: удалить из EXO все лишнее, оставив работу только с одним языком. (Зачем двойной набор одинаковых функций чтения русских и английских фрагментов текста, когда переключение голосов с русского на английский можно обеспечить расстановкой в тексте управляющих тегов). Обратите еще внимание, как в EXO реализовано блочное чтение теста. Поучительно, не правда ли?
Итак, в Demagog добавлена поддержка SAPI5, благо было, на чей опыт опереться. Конечно, я не списывал все буквально у Брайана Лонга. К примеру, он (а вслед за ним автор EXO) употребили для останова чтения команду SpVoice.Skip('Sentence',MaxInt), что привело к большим неприятностям с некоторыми движками (см. выше). Вот как правильно: SpVoice.Speak('',SVSFPurgeBeforeSpeak).
Замечу, что для компиляции проекта уже не получится использовать Turbo Delphi 2006, где отключена опция импорта компонентов.
| Ходы кривые роет подземный умный крот. |
| Нормальные герои всегда идут в обход! |
| Глупцы, героев строя, бросаются вперед. |
| Нормальные герои - всегда наоборот. |
| В обход идти, понятно, не очень-то легко. |
| Не очень-то приятно и очень далеко. |
| Зато так поступают одни лишь мудрецы, |
| Зато так наступают одни лишь храбрецы. |
| И мы с пути кривого ни разу не свернем! |
| А, надо будет - снова пойдем кривым путем! |
| Песенка из кинофильма "Айболит-66" |
"Ну, хорошо", - скажет читатель, забредший на эту страничку, - "Списал у одного - плагиат, списал у нескольких - компиляция, списал у многих - диссертация. А свои-то идеи у автора есть?" На этот вопрос отвечаю положительно.
Что самое главное для голосового движка? Словарь корректировки произношения, ибо учесть все нюансы живого языка никаким гениям программирования не под силу. Создатели голосовых движков иногда предусматривают в своих творениях систему поддержки корректировочных словарей, а иногда - нет. Кому как вздумается и кто во что горазд. Видимо поэтому, Антон Рязанов, автор одной из первых работоспособных программ чтения текстов - "Говорилки" придумал универсальный формат словарей произношения, т.н. dic.
| # Так выделяются комментарии |
| рыцарский замок=рыцарский за<мок |
| нет=не<тЪ |
| $Варя=Ва<ря |
| ##=номер |
| $$100=сто долларов |
| # Звездочки справа и/или слева обозначают |
| # так называемое "сравнение по маске" |
| туник*=туни<к |
| *графии=гра<фии |
| *автобус*=авто<бус |
| $Серов*=Се>ро<в |
| *го гнезда=го гнезда< |
| *, то есть=, то<есть |
Принцип понятен. При этом, в первую очередь рассматриваются правила с самыми длинными левыми частями.
Фраза "Иван Петрович Серов - профессор этнографии, нашарил в кармане туники последние $100 и решил ехать на автобусе" после подстановок примет вид: "Иван Петрович Се>ро<в профессор этногра<фии нашарил в кармане туни<ки последние сто долларов и решил ехать на авто<бусе".
# и $ - соответственно, знаки комментария и учета регистра букв при заменах. Чтобы употребить их, просто как символы, их надо удвоить. То же относится и к символу *. Иначе звездочки справа и/или слева обозначают т.н. сравнение по маске: оно считается удачным, если обеспечено совпадение с указанной частью слова. Под одну маску могут подходить разные, но частично совпадающие слова. Знаки < > - основное и вспомогательное ударения для движка Nicolai. Для других движков знаки ударения - другие или их может не быть вовсе. Тогда эффект ударения можно получить удвоением гласной и т.п. В общем, свобода и воля. Универсализм.
Алгоритм замен очень прост и интуитивно понятен. Каждое правило из словаря применяется ко всему тексту. Правила применяются в порядке убывания длин их левых частей. Т.е. первым будет проверяться правило с самой длинной левой частью. Это логично: сперва в тексте должны заменены самые большие фрагменты. Правила с левыми частями одинаковой длины применяются в том порядке, в каком они расположены в словаре. Как только обнаружено совпадение, так тут же в тексте делается замена и т.д. до конца текста.
В жизни это выглядело бы так. Пусть нам нужно перевести с английского некую интересную книжку. В руках у нас англо-русский словарик, слов эдак на 20 тысяч. Берем 1-е слово из словаря. Читаем книжку от начала до конца в поисках этого слова. Затем переходим ко 2-му слову в словаре и снова читаем книжку целиком. И т.д. пока словарь не закончится.
Слышу голос читателя: "БРЕД!!!"
Согласен. Именно такую бредятину часто пишут программисты, уповая на мощь современных компьютеров. Это называется "прямой перебор".
Те, кто пользовался "Говорилкой", заметили, что она делает легкие паузы через каждые 4-5 предложений. Именно такими мельчайшими порциями программа читает текст. Словарные замены занимают в этом случае доли секунды. Но заминки в чтении уже ощутимы.
Можно заменить функции поиска и замены (простите за каламбур) их ассемблерными аналогами. Есть еще несколько дополнительных технических приемов для снижения трудоемкости прямого перебора. В результате всё будет работать в несколько раз быстрее, нежели в описанной выше бесхитростной реализации. А можно пойти другим путем.
"Швейная машинка Зингера отличается тем, что отверстие для нитки расположено на конце иглы". Здесь мы рассмотрим алгоритм, отличаеющийся тем, что проверяются все слова из текста в поисках совпадений в заранее составленной хеш-таблице.
Как, на самом деле, мы переводим текст со словарем? Мы смотрим сперва в книгу, а не в словарь! Взявши очередное слово из текста, мы ищем его в словаре. Благодаря алфавитным высечкам на его страницах поиск нужного слова занимает секунды.
Еще лучше сказочная ситуация, когда в книге над каждым словом был бы мелкими цифрами напечатан номер страницы, где его искать в словаре. По сути, именно это я и сделал.
Вспомним, что каждый символ текста имеет в компьютерном представлении числовой код. Комбинируя (специальным образом) коды всех букв в слове, я получаю адрес - номер строки хеш-таблицы, где его искать. Как составлена хеш-таблица? Обработкой файла словаря: для каждого правила вычисляется адрес его первого слова. Разумеется, может быть несколько правил с одинаковым первым словом (видеть | видеть звезды=видеть звёзды | видеть стены=видеть сте<ны | видеть цвета=видеть цвета<). Тогда в одну строку хеш-таблицы сядет целое словарное гнездо.
Правила, попавшие в одно словарное гнездо, необходимо расположить в порядке убывания длин их левых частей. Тем самым, хоть и не напрямую, но выполняется требование стандарта словарей DIC о порядке применении правил к тексту.
Правила со звездочками обрабатываются наравне с остальными, звездочка - тоже "буква". В итоге, каждое правило находится строго на своем месте, откуда будет взято в нужный момент.
Каждое слово может быть найдено в хеш-таблице как одиночное, или как первое в словосочетании. Если, вычислив адрес слова, мы в хеш-таблице обнаружили пустую строку - значит, этого слова в словаре нет. Поехали дальше? Не будем спешить. Не нашли слова "похлебка"? Перебираем все его "огрызки", отбрасывая по одной букве справа и слева и добавляя звездочку с той стороны, где отсечены буквы. Для каждого варианта вычисляем адрес. Ищем. Мимо? Следующий огрызок. Наконец-то! *охлеб* | *охлеб*=охлёб. Делаем замену и проверяем следующее правило в этом же словарном гнезде. Когда проверка гнезда будет закончена, то перейдем к следующему слову в тексте.
Проверка словосочетания на совпадение с правилом из словаря проводится сравнением по маске каждого слова в левой части правила со словами, входящими в словосочетание. В результате получилось расширенное толкование правил со звездочкой. Она может находиться не только в конце и/или начале левой части правила, а в конце и/или начале любого слова в левой части правила. Например, чтобы задать произношение фраз: "У ворот города началась битва", "Изменников повесили на воротах города", "Над воротами города реяли стяги", достаточно одного правила: ворот* города=воро<т го<рода.
Если в правой части замен больше, чем шаблонов в левой, то "лишние" замены предварительно объединяются, чтобы избежать конфузий наподобие: *- неп*=- не' п | Это- неправильно => Это- не'равильно п . Здесь замены не' п надо считать за одну, тогда обе части правила станут сбалансированы.
Аналогично, если в левой части шаблонов больше, чем замен в правой, то справа добавляется необходимое число "пустых" замен. Слово, которому целиком досталась такая замена, исключается из рассмотрения. А еще бывает, что после пустой замены от слова остается одна "задняя" часть. Такой обрубок логично присоединить вплотную к предыдущим словам. Вот: *к что о*=к_что_о (пусто) (пусто) | так что он => так_что_он . В этом примере продемонстрировано исчезновение слова "что" и превращение слова "он" в несамостоятельный охвосток "н".
Разные мелочи вроде оптимального размера хеш-таблицы, разрешения коллизий и т.п. опускаю. Читайте библию от Д.Кнута "Искусство программирования" т.3 "Сортировка и поиск", глава 6, раздел 4 "Хеширование".
Скорость работы этого алгоритма практически на порядок выше, чем у "бесхитростной" версии метода прямого перебора. Конечно, его реализация требует от программиста бОльших усилий. Сравните: сколько слов я потратил на описание прямого перебора, а сколько на "хеш-алгоритм"?
В результате Demagog может безбоязненно глотать куски текста намного большие, чем абзац. По умолчанию я поставил 4096 символов - примерно книжная страница.
Множественные замены. Как отмечалось выше, вполне возможна ситуация, когда некоторая часть слова меняется по одному правилу, другая часть - по следующему и т.д. Ведь алгоритм, рассматривая один за другим, "огрызки" данного слова, не останавливаемся после первой замены, а проверяет следующие.
И ему по зубам фразы типа: "Злостная антисоветчица - это devochka, vsegda неправильно подсказывающая товарищам na urokah". В слове "антисоветчица" производится 2 замены (анти'сове<тчица), в слове devochka - 7. Корректно отрабатываются и двойные замены вида "простое правило - сложное правило": *ическ*=и<ческ | *ого ко<рпуса ; металлического корпуса => металли<ческого ко<рпуса. Или: *даленн*=далённ | *ые земли=ые зе<мли ; отдаленные земли => отдалённые зе<мли. Могут быть случаи, когда различные части слова расщепляются на несколько слов, а остальные меняются по правилам транслита: http://arnys@mail.ru => эйч ти ти пи.арнис, сабака, мэйл точка ру - 11 замен.
"Звездные правила". Если левая часть правила состоит только из звездочек, (быть может, разделенных пробелами), то все звездочки считаются просто символами. Сравнение с текстом производится не по маске, а на простое равенство строк. Например:
| * * *=...новый раздел... | - заменяется строка * * * |
| *= | - заменяется (на пустую) строка * |
Видим, что удвоения оконечных звездочек, применяемого в классическом формате dic, не требуется! Тем самым мы избавлены от необходимости сочинять нелогичности, вроде: *****=три звезды | **=одна звезда.
А еще алгоритмом принципиально игнорируются вот такие дикие правила: *пробелы=пробел. Для прямого перебора они имели некоторый смысл - замена в тексте нескольких идущих подряд пробелов одним. У нас же все они превратятся в *= . А если этого правила в явном виде в словаре нет, то и не надо, чтобы оно невесть откуда возникало.
Остается рассмотреть случай, когда отдельно стоящая звездочка соседствует с "нормальными" шаблонами и имеет равные с ними права. Неужели это будет работать?! Ведь под маску из одной только звездочки подойдет любое слово в тексте! Успокойтесь и дышите глубже. По правилу: * то есть=то<есть в тексте будет найдено любое слово, за которым идут слова то есть. Найденное слово не подлежит замене, заменятся лишь следующие за ним, конкретизировавшие поиск слова. Простая, то есть - несложная. => Простая, то<есть - несложная.
Еще круче: все * *ло=всё ло | Все давно прошло. => Всё давно прошло. | Все вокруг потемнело. => Всё вокруг потемнело. | Все мне надоело. => Всё мне надоело. И так далее... Чёртова уйма вариантов с омографом ВСЕ/ВСЁ решается одним правилом.
Заметим, что классический формат dic в этом отношении бессилен, ничего, кроме нудного добавления каждой из вариантных строк в словарь он предложить не может.
Что в итоге? Проверка на большом тексте (15мб), с подключенным "великим и ужасным" словарем Michelangelo.dic показала, что измененный словарными подстановками текст на 99.797% совпадает с результатами классического прямого перебора ("Балаболка"). Вполне удовлетворительно.
Нормально выполняются даже такие (лично меня приводящие в содрогание) правила:
| $*. а=. А | Мы – нет. а вы? => Мы - нет. А вы? |
| $*! а=! А | Вы – нет! а мы - да. => Вы – нет! А мы – да. |
| $*? а=? А | Вы – нет? а мы - да. => Вы – нет? А мы – да. |
| $*- а=- А | Вышло- а как же... => Вышло- А как же... |
На этом пора поставить точку и отложить перо (тьфу, клавиатуру) в сторону.
У нас получился быстродействующий алгоритм с расширенным толкованием стандарта DIC: 1) звездочки могут находится не только в начале и/или конце левой части правила, а в начале и/или конце любого слова в левой части правила; 2) звездочки могут стоять там отдельно, обозначая любое слово проверяемого текста; 3) если в левой части правила - одни лишь звездочки, то они понимаются, как просто набор символов, подлежащих замене.
4. X-files. (Секретные материалы)
| Говорил, ломая руки, | Смотрите сюда... Это основная схема... |
| Краснобай и баламут | Это просто, как дважды два. |
| Про бессилие науки | Чистая случайность, что это до сих пор |
| Перед тайною Бермуд! | не было построено. |
| В.Высоцкий "Письмо в редакцию" | А.Н.Толстой "Гиперболоид инженера Гарина" |
Тайна "быстрого алгоритма". Допустим, в словаре есть 2 правила, расположенные в следующем порядке:
| *ащенн*=ащённ |
| ... |
| *враще*=враще< |
Как будет выглядеть измененное слово"возвращенный"? При прямом переборе правил получим верный результат: возвращённый. Ибо правила с одинаковой длиной левых частей выполняются в порядке их следования в словаре. А вот как работает наш алгоритм. В хеш-таблице образуется два словарных гнезда:
| *ащенн*|*ащенн*=ащённ |
| ... |
| *враще*|*враще*=враще< |
Их местоположение в хеш-таблице и порядок следования заранее неизвестны, да и не имеют значения. И вот какое гнездо будет выбрано при проверке упомянутого слова. СмотрИте:
| возвращенный |
| ... |
| возвр |
| озвра |
| звращ |
| враще |
| ращен |
| ащенн |
| ... |
Результатом будет: возвраще<нный. Выбор словарных гнезд происходит в том порядке, в каком генерируются ключи поиска процедурой Trunks! И как бы мы не переставляли местами сии 2 правила в словаре - итог будет один и тот же. Неутешительный. Потому что в "быстром алгоритме" в нужном порядке проверяются лишь правила, сидящие в одном словарном гнезде. А пока не сгенерирован следующий ключ, мы даже не знаем о существовании (или не существовании) очередного словарного гнезда. И не сможем понять, что текущая замена - преждевременна и делать ее не надо. Ибо найдется лучшая.
Это - недостаток "быстрого алгоритма". Проявляющийся на частично пересекающихся правилах. Они ложатся в разные словарные гнезда (при том, что могут подходить к одному и тому же слову!) и мы имеем то, что имеем... Где-то так 1 раз на 1000. Но для больших текстов - вполне может быть. Для нашего алгоритма решением было бы: взять, да переделать проблемные правила, ибо нехорошо, когда одно правило является, по сути, продолжением другого.
Почему никто не додумался раньше? Как было сказано, в словарях формата DIC правила положено применять к тексту в порядке убывания длин их левых частей. Символ * в подсчет длины не входит. Если эта длина для 2-х правил - одинакова, то они применяются в порядке их следования в словаре.
| ПРИМЕР 1 |
| Правила: |
| *^*= |
| муха=слон |
| Текст: м^у^ха |
Первым применяется правило с самой длинной левой частью: муха=слон. Оно - не подходит к тексту - замен нет; Затем выполняется правило *^*= - оно подходит, две замены. Просмотр словаря закончен, останов.
Измененный текст: муха
Всё верно. Но отчего-то кажется, что здесь что-то не так... А, вот оно что! Интуитивно мы ожидали, что правило *^*= сработает первым. Ведь оно и предназначено для предварительной подготовки текста. Увы - это противоречит давно устоявшемуся стандарту словарей DIC, по которому сначала проверяются длинные замены (что, кстати, вполне логично).
Но... Если к измененному тексту снова применить тот же словарь? Итак, всё сначала. Правило: муха=слон - теперь подходит! Одна замена. Правило: *^*= уже не подходит, свою службу сослужило раньше. Словарь исчерпан, останов.
Вторично измененный текст: слон.
!!! Приходим к очевидному обобщению. Применять замены к тексту НЕ однократным проходом по словарю, а повторяя этот процесс до тех пор, пока он приводит к изменению текста.
Однако, на этом пути нас подстерегает засада.
| ПРИМЕР 2 |
| Правило: *чертя*=чертя< |
| Текст: очертя |
| Измененный текст при многократном обращении к словарю: |
| очертя< |
| очертя<< |
| очертя<<< |
| и т.д. до морковкина заговенья. |
Во избежание подобных казусов, должен вестись список уже примененных правил, и каждый раз применяться лишь те правила из словаря, которых еще нет в этом списке. Тем самым гарантируется конечность алгоритма.
Насколько будут отличаться тексты, измененные в традиционном и в только что предложенном порядке? Примерно на 0.1% в среднем. Так стоила ли игра свеч?
Полагаю, что да. Ведь текст (на любом языке) представляет собой т.н. "последовательность редких событий". Многие слова, несущие реальную смысловую нагрузку, встречаются в нем всего лишь несколько, а то и вовсе один раз! Оставаясь при том важными для понимания текста. Поэтому, улучшение алгоритма словарных замен, касающееся даже небольшой доли слов в тексте, может оказаться полезным.
Кроме того, нисколько не погрешив против принципа применения правил в порядке убывания длин их левых частей, мы фактически сняли это ограничение. А именно, когда короткие правила используются для очистки текста от "мусора". Более "содержательные" правила уже будут успешно применены при последующих проходах по словарю. Аналогично - при раскрытии условных сокращений и аббревиатур. И т.д. и т.п.
| ПРИМЕР 3 |
| Словарь: Michelangelo.dic |
| Текст: Devochka Nina - korr. CNN |
| Измененный текст: Де<вочка Нина - корреспонде<нт Си энээ<нн |
| Примененные правила: |
| 1-й проход: а) раскрыта аббревиатура; б) текст очищен от транслита |
| cnn=си энээ<нн |
| *ch*=ч | *a*=а | *d*=д | *e*=е | *i*=и | *k*=к | *n*=н | *o*=о | *r*=р | *v*=в |
| 2-й проход: а) применено правило постановки ударения; б) раскрыто условное сокращение |
| девочк*=де<вочк |
| *корр.=корреспондент |
| 3-й проход - применено правило постановки ударения |
| корреспондент*=корреспонде<нт |
Грех не воспользоваться открывшимися
возможностями. Поэтому, в настоящее время в Demagog'e
используется ново-классический
(скажем так) алгоритм словарных замен. Не утомляя никого подробностями,
приведу основную схему:
1) Проверка ведется по словарю в целом;
2) Правила применяются в порядке убывания длины их левых частей. Символ * в подсчет длины не входит. Примеры: $ПВО - длина 4; $*O* - длина
2; *u* - длина 1; $* - длина 1; * - длина 0; и т.д. и т.п.;
3) Правила одинаковой длины применяются в том порядке, в каком стоят в
словаре;
4) Сохранены все нововведения "быстрого алгоритма" касательно звездочек внутри левых частей правил. Наподобие: ворот* города=воро<т го<рода | все * *ло=всё ло | * * *=три звезды;
5) В отличие от традиционной практики, правила применяются к тексту не однократной проверкой по словарю, а до тех пор, пока возможно.
Скорость работы составляет в среднем 68.5% от "быстрого алгоритма". Зато отсутствует отмеченный выше недостаток, проявлявшийся в чересчур поспешном выборе подходящих правил.
Как и раньше, использованы лишь стандартные средства Delphi. А подтверждением правильности послужило совпадение результатов классического и ново-классического алгоритмов, составившее 99.850%. Оставшиеся 0.15% объясняются: а) иным принципом разбивки текста на слова, в Demagog'e разделителем слов считается только символ пробела; б) более полным применением правил в ново-классическом алгоритме. (А если просмотр словаря выполнять по старинке: однократно, то показатель совпадения составит 99.906% - хорошее равенство до 3-х девяток)
5. Свежий взгляд
| Поила старая старушка |
| Меня молочным молоком, |
| И я глотки глотал из кружки, |
| Языча губы языком. |
| Потом буханку с хлебным хлебом |
| И маслом масляным сжевал, |
| И под небесным синим небом |
| Про это рифмы рифмовал. |
| Смеялась бабка, как чумная, |
| Потом сказала, щуря глаз: |
| "Как для издательства - не знаю, |
| А для пародий - в самый раз!" |
| Александр Матюшкин-Герке |
В 1999 г. Д.Кирсанов написал утилиту Fresh Eye для поиска в тексте фонетически и морфологически схожих слов, стоящих "слишком близко" (http://www.kirsanov.com/fresheye).
Наткнувшись случайно на нее в Интернете, я решил посмотреть, как это все работает. Начал с очевидного:
Карл украл у Клары кораллы, Клара украла у Карла кларнет.
Как ни менял в настройках т.н. "порог чувствительности" - ответ получался один: проверено 1, найдено 0. А в стихах про старушку и поэта (при пороге чувствительности, принятом по умолчанию), отыскалось лишь 2 повтора: "маслом масляным" и "рифмы рифмовал". Ну и пусть... Одобрения заслуживает сама идея анализа текста на повторы, за каковую и спасибо.
Первым делом, необходим метод приблизительного сравнения слов. Можем же мы прочесть следующий текст:
По рзелульаттам илссеовадний одонго анлигйсокго унвиертисета, не иеемт занчнеия, вкокам пряокде рсапожолены бкувы в солве. Галвоне, чотбы преавя и пслоендяя бквуы блыи на мсете. Осатьлыне бкувы мгоут селдовтаь в плоонм бсепордяке, все-рвано ткест чтаитсея без побрелм. Пичрионй эгото ялвятеся то, что мы не чиатем кдаужю бкуву по отдльенотси, а все солво цликеом.
Попробуем формализовать интуитивный процесс, благодаря которому мы поняли, что здесь написано. Определим коэффициент "похожести" двух слов, подсчитав, сколько символов из первого слова содержаться во втором. Но такой алгоритм не способен различать анаграммы и перевертыши. Например, слова "колесо", "оселок", "окосел" будут восприняты, как одинаковые.
Усложним процедуру, добавив проверку на присутствие 2-буквенных подстрок первого слова во втором. Потом 3-х буквенных... не пора ли остановиться? Средняя длина слова в русском языке - 6 букв. Хотите верьте, хотите нет, но перебором 3-х буквенных подстрок (ровно половина от 6) можно ограничиться. Число успешных поисков поделим на общее число подстрок - это и будет показатель сходства.
Примеры:
КОЛЕСО, ОКОСЕЛ. По отдельным буквам 6 попаданий из 6. 2-х буквенные: КО, ОЛ, ЛЕ, ЕС, СО - 1 из 5. 3-х буквенные: КОЛ, ОЛЕ, ЛЕС, ЕСО - 0 из 4. Результат: (6+1+0)/(6+5+4) = 0.467.
АРБУЗ, ТАРАКАН. 2 из 5; 1 из 4; 0 из 3. Результат: 3/12 = 0.250.
ТАРАКАН, АРБУЗ. 4 из 7; 1 из 6; 0 из 5. Результат: 5/18 = 0.278.
Видим, что "сходство", вообще говоря, не транзитивно. Поменяв порядок сравнения, можно получить иной результат. Из двух ответов возьмем больший, только и всего.
Похожий алгоритм предложен в 1998 г. Владимиром Кива и называется "алгоритм нечеткого сравнения строк". Транзитивность операции сравнения достигается одновременным подсчетом подстрок одинаковой длины первого слова во втором и второго в первом. Такой вариант обладает меньшей чувствительностью. Например: (AB, ABCDE) - у меня будет 1 (т.к. одна строка целиком содержится в другой), а по Кива - всего 0.4. И тот и другой подход по своему логичны. Мой алгоритм видит рифмы. Однако, во избежание массы ложных срабатываний, надо сразу исключить сравнение со словами, короче 3 букв (это, в основном, предлоги, союзы, междометия), а среди 3-х буквенных выкинуть из рассмотрения наиболее частые. (Таких, покрывающих 90% всех "трехбуквенников" в любом тексте - в русском языке чуть больше полусотни).
Стихотворный эпиграф в начале главы расцвечен синим и красным - "масляные масла", найденные при коэффициенте "сходства" >= 0.5. Конечно, повторы в художественных текстах - совсем не обязательно признак неопытности автора. Зачастую они привносят в произведение дополнительную смысловую и эмоциональную составляющую. Поэтому, не станем объявлять графоманом великого писателя земли русской.
|
В это время в гостиную вошло новое лицо. Новое лицо это был молодой князь Андрей |
|
Болконский, муж маленькой княгини. Князь Болконский был небольшого роста, весьма |
|
красивый молодой человек с определенными и сухими чертами. Все в его фигуре, |
|
начиная от усталого, скучающего взгляда до тихого мерного шага, представляло |
|
самую резкую противоположность с его маленькою, оживленною женой. Ему, видимо, все |
|
бывшие в гостиной не только были знакомы, но уж надоели ему так, что и смотреть на |
|
них и слушать их ему было очень скучно. Из всех же прискучивших ему лиц, лицо его |
|
хорошенькой жены, казалось, больше всех ему надоело. |
|
|
6. "Глокая куздра", "четыре четырки" и Питон
| Вспыхает небо, разбужая ветер, | Пусть безумная идея - |
| Проснувший гомон птичьих голосов. | Не рубите с горяча. |
| Проклинывая все на белом свете, | Вызывайте нас скорее |
| Я вновь бежу в нетоптанность лесов. | Через гада главврача! |
| Шуршат зверушки, выбегнув навстречу, | С уваженьем... Дата. Подпись. |
| Приветливыми лапками маша - | Отвечайте нам, а то, |
| Я среди тут пробуду целый вечер, | Если вы не отзоветесь, |
| Бессмертные творения пиша. | Мы напишем... в "Спортлото"! |
| Но, выползнув на миг из тины зыбкой, | |
| Болотная зеленовая тварь | В.Высоцкий "Письмо в редакцию" |
| Совает мне с заботливой улыбкой | |
| БОЛЬШОЙ ОРФОГРАФИЧЕСКИЙ СЛОВАРЬ. | |
| Александр Матюшкин-Герке |
Demagog умеет говорить и анализировать текст на повторы и созвучия. А хорошо бы в придачу иметь (пусть даже простейший) контроль орфографии. Ведь так нередки в текстах АшиПки и оЧеПЯтки...
Разумеется, можно подключаться к MS Word средствами OLE Automation. Уж в Ворде-то проверка орфографии реализована, так пусть он и делает всю работу за нас. Правда, возникнут сложности с разными версиями Ворда. Что 2003-му здорОво, то 97-му - смерть... Да и странно это - превращать изящную в своей компактности программу в заурядный придаток при некоем монстре. Есть ли другие пути?
Одна идея, словно призрак коммунизма, бродит
среди лингвистически настроенных умов, начиная с середины прошлого века.
Только-только появились первые ЭВМ... Это означало: электронная
вычислительная машина, слово "компьютер" еще не придумали, но придумали
"кибернетику" - буржуазную лженауку для запугивания рабочего класса
.
Тут-то кое-кого и осенило.
Суть гениального (не знаю, нужны ли в этом слове кавычки) озарения такова. Количество 2-буквенных сочетаний в русском алфавите: 33 x 33 = 1089. А допустимых из них: раз-два и обчелся. Можете самостоятельно составить квадратную табличку и вписать в нее все "разрешенные" комбинации. Простейший алгоритм, считай, готов.
Безумие этой идеи в том, что минимальный набор проверочных комбинаций охватывает все потенциально возможные слова русского языка! Становится ненужным огромный словарь-тезаурс, где каждое слово надо указывать во всех падежах, наклонениях, спряжениях и т.п. (Ведь даже тезаурус системы Ispell на 850 тыс. словоформ, на практике оказывается не вполне достаточным).
Но... (спускаясь с небес на землю), мы скоро заметим, что из 2-буквенных комбинаций можно понаделать еще больше невозможных, несуществующих слов. Все они, естественно, были бы при проверке признаны "правильными". Глокая куздра штеко будланула бокра и курдячит бокренка - здесь только допустимые пары букв!
Очевидно, необходимо ужесточить схему, проверяя на допустимость не 2-х буквенные, а 3-буквенные сочетания. Тогда для составления проверочного списка придется прошерстить уже 33 x 33 x 33 = 35937 троек в поисках правильных. Еще более надежным решением будет проверка "четырок". Например, в слове "демагог" - четыре четырки: дема/емаг/маго/агог. Все они - допустимые. Из общего числа в 1185921 - таких найдется тысяч 35-40. Проверяя все четырки заданного слова на допустимость, делаем вывод о верном или неверном его написании. Все упомянутые в Интернета изыски по бессловарной проверке орфографии на этом исчерпываются.
Поразмыслив, можно найти примеры, когда и такая схема слишком уж всеобъемлюща. Блинны. Это слово не опознается, как ошибочное, т.к. 4-ка линн - допустимая. (Длинный). Песьмо - из той же оперы - песь - спесь - песьими. Надо что-то делать...
Попробуем перейти к проверке 5-ти буквенных сочетаний. Весело, дружно, хватаем бревнышко и несем... Что нам стоит среди 39135399 (39 миллионов с хвостиком) вариантов отыскать "правильные пятерки"?
Скрипт на языке сверхвысокого уровня Python, за считанные минуты решающий эту задачу.
Говоря словами О.Генри: он "прост, как молодой редис и незатейлив, как грабли". Написание и отладка первого варианта заняли 1 час. Все потому, что Питон избавляет программиста от массы рутинной работы. Использовалась версия языка 2.4.4.
С помощью этого скрипта обрабатывается ОЧЕНЬ большой текст.
Это - основное требование к тексту, чтобы он был громадным.
Во-вторых, он не должен содержать знаков переноса на концах строк.
В-третьих, он должен быть общехудожественным, а не специализированным.
Я составлял "большой текст" по частям, "склеивая" из отдельных файлов. В одном из них потребовалось удалить все знаки переноса - здесь помог Demagog. В итоговый bigtext.txt, размером 15 Мб, вошло с дюжину романов. Названий не привожу, произведения отбирались не по величию авторов, а по величине текста. Так быстрее получался должный объем "словесного материала". Разумеется, я пытался придерживаться принципа "общехудожественности". Никаких физико-математико-философских работ с заумно-языколомной терминологией! Литературные произведения только вменяемых авторов... Мы же собираемся проверять орфографию русского языка.
Оставалось набрать командную строку: python orfo.py bigtext.txt ignore.txt и через несколько минут я получил требуемый список "пятерок".
Насколько он полон? Вот как менялся размер списка с ростом объема текста:
| Объем текста, мб | Количество найденных "пятерок", тыс. |
| 0 | 0 |
| 3.2 | 48.0 |
| 6.8 | 77.1 |
| 10.9 | 88.2 |
| 14.2 | 94.8 |
| 15.0 | 99.5 |
| ... | ... |
Каждая очередная порция текста добавляла все меньше и меньше нового. Вдалеке просматривается некий предел? Пополнять bigtext.txt новыми шедеврами мне надоело, да и обработка его скриптом стала занимать аж целых 3 минуты - что же будет дальше? Решил пойти на хитрость. Нашел в Интернете частотный словарь русского языка на 69307 наиболее употребительных словоформ и скормил скрипту. Вышло, круглым счетом, 60 тыс. пятерок - так сказать, необходимый минимум. Добавил сей чудный словарь в bigtext.txt... На выходе - 103 тыс. - прирост совсем уже невеликий. Тот же фокус можно проделать с тезаурусом системы Ispell. Из 850 тыс. наивозможнейших словоформ выходит 150 тыс. пятерок. Но тезаурусы Ispell составляются автоматически по принципу добавления к корням слов всех возможных приставок и окончаний, и содержат много маловероятных, практически неупотребляемых вариантов. Подучилось - нечто среднего рода повысило свои знания в некоторой области. А ведь, скорее всего, "подучилось" - это неверное написание слова "получилось"! Вот так: сильно хорошо - тоже плохо. От чрезмерного расширения списка эффективность отлова ошибок и опечаток начинает снижаться! Практика показывает, что 100 тыс. пятерок, полученных обработкой текстов общеупотребительной лексики - вполне достаточно.
Второй параметр скрипта - это список "запрещенных" слов. В любом, даже весьма тщательно составленном тексте, возможны опечатки. Чтобы их выявить, совсем не нужно выверять текст заранее. Первый запуск: python orfo.py bigtext.txt даст черновой вариант списка, в котором для каждой пятерки указано, сколько раз она встретилась в тексте. Для пятерок, встретившихся в тексте не более 3 раз, указываются также слова, их породившие. Именно среди них беглый просмотр позволяет выявить опечатки, жаргон и пр. Я заносил в черный список только явные ошибки, церковнославянизмы и англосаксонизмы. А также фантастические / фэнтезийные термины и мат.
Повторный запуск, уже с указанием второго параметра, даст очищенный список пятерок. Сокращение небольшое, но заметное - несколько тысяч.
Помимо этого, скрипт изначально игнорирует все слова, написанные большими буквами, или начинающиеся с таковой. Тем самым отметаются имена собственные и географические названия. Жаль, конечно, казака Дормидонта Семижопенко из ст. Старонижнемухосранской, но зато избавляемся от всяческих Хзкхкхрх Рхрч, Жугдэрдэмидийн Гуррагча, Ыгыатта, Таллинн, Кыргызстан и т.д. и т.п. и пр. и пр. Пропускаются также слова с цифрами, нерусскими буквами и написанные через дефис. Буква ё всюду заменяется на е.
Считаются недопустимыми слова, содержащие 3 одинаковых буквы подряд, за исключением фрагмента "ошеее". Слова со следующими друг за другом парами одинаковых букв также не берутся во внимание, если только это не пары: еенн, ллее, ллии, ллоо, ннее, ннюю, нняя, ссее, ссии. Теперь не страшны разные Уурраааа!! Аррггх-брруумм! Тра-татата!! и тому подобные гремящие комбинации, которыми некоторые авторы "оживляют" повествование. Шутки шутками, но удается избавиться от изрядного количества мусора в обрабатываемом тексте.
В полученной орфотаблице для каждой пятерки указывается также ее код. 100x - пятерка встречается только в начале слова; 010x - только в середине; 001x - только в конце. Возможные комбинации: 110x, 011x, 101x, 111x. x = 1 для буквосочетаний, которые могут быть самостоятельными словами и 0 в противном случае. Очевидно, что слова короче 5 букв имеют код: 0001.
Кроме основной орфотаблицы, создается краткая. В ней присутствуют только пятерки и их коды, причем коды тоже записаны в сжатом виде. Четырехзначное двоичное число экономнее представлять в виде однозначного 16-ричного. Размер файла орфотаблицы тем самым уменьшается на треть.
Посмотрим,как это работает. Красавчег = краса / расав /савче / авчег. Найдено в орфотаблице: краса 1111. 5-ка может находится в начале слова; расав 0100 - только в середине, она там и находится; савче - НЕТ В ТАБЛИЦЕ. ОШИБКА. Нарей мне стакан воды! В таблице есть: нарей 0110 - может находится только в середине или конце слова (канарейка, фонарей). ОШИБКА.
Нажатием клавиши F4 проверяется выделенный текст. При формировании орфотаблицы я старался не пропускать в обработку составные слова, потому что на "стыках" входящих в них "простых" слов могут получаться нехарактерные, редкие буквосочетания, которые лишь зря замусорят таблицу. Но составное слово можно проверить, по очереди выделяя отдельные его части; или разделив их пробелами или дефисами и, затем, выделив все целиком.
ПРЕДУПРЕЖДЕНИЕ для
энтузиастов, которым захочется переделать скрипт, чтобы проверять 6-ти
(и более)
буквенные сочетания. Проверка станет работать хуже и чем дальше, тем хужЕе
.
Все потому, что орфотаблица начнет постепенно превращаться в тезаурус, разбухать
в размерах, ведь в нее заведомо потребуется включать все словоформы не
длиннее n, где n = 6, 7, 8...
Кстати, n идущих подряд букв в слове называются n-граммой, этим термином и будем дальше пользоваться. В нашем случае n = 5.
Еще раз подчеркну принципиальное отличие n-граммного метода проверки орфографии от словарного. Например, в bigtext.txt, использованном для построения орфотаблицы, и в помине не было вот этих слов, которые MS Word в панике подчеркнул красным:

Интуитивно эти слова вполне понятны и кажутся написанными правильно! В определенном смысле это так и есть. Все содержащиеся в них 5-граммы, получены обработкой других слов из bigtext.txt и являются допустимыми. И для n-граммного метода вышеприведенная фраза - верна. Но попробуйте написать: полнавироятная, нипонятица, злоупотребительстуйте, наиперемурденностью... Эти слова (опять же, в полном согласии с нашей интуицией!) будут отбракованы.
Создается впечатление, что n-граммному методу присущ своеобразный "интеллект". Конечно, даже при n=5 он пропускает, как якобы верные, несуществующие слова. Но... они выглядят довольно естественно, укладываются в рамки статистических закономерностей языка.
В общем и целом, метод уверенно различает тексты, написанные с ошибками и без.
Стихи А.Матюшкина-Герке в эпиграфе этой главы расцвечены красным - слова которые и MS Word и Demagog дружно объявили ошибочными и синим - слова, которые только Word счел неправильными. Вполне удовлетворительно; как и ожидалось, орфотаблица из 105 тыс. элементов - достаточно полна.
Это - обычный текстовый файл, даже не отсортированный по алфавиту, ибо для Demagog'a порядок следования элементов в орфотаблице безразличен.
Содержимое орфотаблицы можно изменять. Но не надо усердствовать, засоряя ее именами собственными и географическими названиями. Они, как правило, не являются осмысленными словами и не подчиняются языковым законам. (Тверьуниверсалбанк. Каково?)
А удаляя какую-нибудь "нехорошую" словоформу, необходимо помнить, что при этом удаляются составляющие ее 5-граммы. В их числе могут оказаться и нужные, правильные, порожденные другими, вполне нормальными словами. Чтобы "возместить потери", придется некоторые слова вносить в орфотаблицу заново. Отсюда правило: если необходимо одно добавить, а другое удалить, то сперва надо выполнить удаление!
Когда выполнена проверка орфографии (хоть маленького фрагмента, хоть всего текста - это занимает секунды, то в окне "Статистика" появится список найденных ошибочных слов, отсортированный по алфавиту. При этом слова, начинающиеся с большой буквы, помещаются в начале списка и отсортированы отдельно.
Кстати, еще о подмеченной нами "разумности" этого необычного, статистического по своей природе алгоритма. Великий писатель А.И.Солженицын составил т.н. "Русский словарь языкового расширения" (М. Русский путь, 2000), о котором многие лингвисты отозвались крайне отрицательно. Вот короткий рассказик, содержащий почти только одни слова из "Расширения".
| Растопыря, или необиходная баба |
| Ерыжливый дурносоп верстан, достодолжный жегнуть шершавку, любонеистово |
| хайлил жиротопное шурьё. Зябкоподжимчивый валява остробучил, жубря: |
| "Хунды-мунды, вахлюй! Отрезно ты фефёлу дочул, иззаплаченный дурандай!" |
| "Да, жемнул я мормотень! – отжегнулся дурносоп верстан, - "а тебе вот |
| маламзя с расщепырей!" "Да, ить здеся одна жирным-жирнешенька шеврюжка!" - |
| верстанулся прощепырник. "А ты чо выхайлился, захухряев оторвяжник?" – |
| утомчился зябкоподжимчивый дурносоп. "Эвося! – защепырил прожубрястый |
| валявка, - "я то – чуфырь! А ёна ведь неутомчивая жемжурка. Коли ей |
| баларыст зажирнить в шабры, так расщепырится захухрястой профефёлой!" |
| Тутока верстаный дурносопяк дочуял страстоубийственный хлясь. Отрезный |
| захухряй прожемнул поконец и ущепырил растопырю. |
Можете сами скормить сей текст Demagog'у, выделить все, затем F4 и полюбоваться результатом. Никаких других доказательств, полагаю, не нужно. Ладно, там MS Word... Если уж и Demagog полностью отвергает это, то "слова" из "Расширения" и, в самом деле, не отвечают строю русского языка.
7. "Экранная лупа" или путями первопроходимцев
Однажды Гарри Поттер забыл где-то свои очки. А надо было срочно прочесть на компьютере кой-какие магические тексты... Что делать?! Близоруко щурясь, юный волшебник нашел на рабочем столе Windows иконку программы Demagog. Когда она загрузилась, Гарри нажал на клавиатуре комбинацию Ctrl+F1... Чтение и навигация на рабочем столе и в окнах программ больше не являлись проблемой.

Что положено в основу? Дополнительная форма с компонентом Timer, с ним связана процедура копирования части экрана и рисования ее на компоненте Image в этой же форме. Первая заповедь программиста: не торопись прошибать лбом стену, а проверь, может ее прошибли до тебя? Поиск в Сети: "Delphi. Экранная лупа" приводит к целому семейству открытых проектов, восходящих к утилите gZoom, которую когда-то написал Zarko Gadjic. Остальные дружно шли по его следам, поскальзываясь, один за другим, на брошенной Zarko арбузной корке.
В результате все
эти изделия через 5-10 мин.
после запуска внезапно, с предсмертным вскриком: "Canvas does
not
allow drawing" отбрасывают копыта. "Недолго музыка играла, недолго фраер
танцевал..." Особенно забавно это выглядит с включенным Диспетчером задач -
видно, как неумолимо, с каждой минутой, растет потребление памяти. На
каком-то дельфийском форуме очередной "разработчик" экранной лупы в отчаянии
вопрошал: "В чем дело? Ведь холст освобожден командой C.Free ???"
Где зарыта собака, я нашел довольно
быстро. А потом обнаружил в Сети самим Zarko
исправленный вариант. Кому
интересно, в чем дело, вот ключевой фрагмент:
| hDesktop := GetDesktopWindow; |
| try |
| C.Handle := GetDC(hDesktop); |
| Image.Canvas.CopyRect(Drect,C,Srect); |
| finally |
| ReleaseDC(hDesktop,C.Handle); {!!!} |
| C.Free; |
| end; |
"Экранная лупа" в Demagog'e - это отдельное, перемещаемое и изменяемое в размере окно, в котором отображаются в увеличенном виде окрестности мышиного курсора. Перекрестие прицела соответствует положению указателя мыши на экране монитора. Если лупа активна (иначе - кликаем по ее заголовку), то крутя колесико мыши, мы можем изменять степень увеличения от 2 до 16 раз.
8. "Говорит и показывает..."
| Интервью с лидером Партии пофигистов. |
| - Почему ваша партия так называется? |
| - Потому что нам все по фигу. |
| - И проблемы экологии? |
| - По фигу. |
| - И экономический кризис? |
| - По фигу. |
| - А... так вы и к деньгам равнодушны? |
| - Э... нет! Деньги - это святое! |
| - А как же ваши принципы? |
| - А по фигу. |
| Старый анекдот. |
Похожая история вышла и с моими принципами. Нет-нет, дело не во внезапном приступе жадности; Demagog как был, так и останется бесплатной программой. Но, в некотором смысле, мои убеждения оказались на поверку такими же гибкими, как взгляды некоего партийного босса. "Если без чего-то можно обойтись, то оно в программу включено не будет" - до сих пор я строго придерживался этого правила.
Голосовые движки понимают только обычный текст, отнюдь не документы MS Word или электронные книги в формате Fiction book. После преобразования оных в просто текст, все картинки, если таковые в исходных документах имелись, будут потеряны. "Это есть факт", всем известный и давно привычный. Жалко, но как-нибудь обойдемся.
Часто ли в современной "бумажной" книжке увидишь хоть одну иллюстрацию? Лишние расходы и хлопоты издателям ни к чему. "Пипл схавает" и так.
Но, все же... все же... Делать ничего не будем, а просто так посидим, подумаем. За компьютером. И Delphi запустим, по привычке.
Лишь на первый взгляд извлечение рисунков из doc, docx, rtf-файла представляется неразрешимой загадкой. Что будет, если средствами OLE Automation заставить MS Word сохранить некий документ, пусть это будет "Алиса в стране чудес.doc", как веб-страницу "Алиса в стране чудес.htm", и сразу ее удалить?
Правильно. Приз в студию. Останется папка с именем "Алиса в стране чудес.files", содержащая все рисунки из первоначального документа. (О том, что для ранних версий Word этот фокус не работает, культурно умолчим).
А что если в Demagog загрузить именно веб-страницу, когда-то выкачанную нами из Сети? Вспомним, что при сохранении веб-страницы, каталог "имя-страницы.files" создается автоматически. Правда, не всегда - иные веб-страницы порождают каталоги с именем: "имя-веб-страницы_files". Программа должна проверять оба варианта названия "каталога-галереи".
Итак, с вордовскими текстами и веб-страницами разобрались. Займемся электронными книгами формата fb2 - заурядными XML-документами. Картинки в них заданы блоками т.н. кода Base64. Например: <binary id="faraon.jpg" content-type="image/jpg">...код...</binary>. Вырезать эдакие подстроки и поместить их в список TStringList, ясное дело, раз плюнуть. Исходник функции Base64decode() возьмем в Сети.
Запишем декодированные бинарные строки в файлы с соответствующими расширениями, поместив их, как нам уже привычно, в папку "что-то там такое.files". Видим, что полученные jpg и bmp-файлы компонентом Image отображаются правильно! А вот с форматом png Delphi не работает принципиально. Ну, не было такого формата в эпоху зарождения и взлета Delphi. Но и здесь дела обстоят не так уж плохо. В Сети лежит-дожидается, пока его скачают, компонент TPNGImage. Все содержимое архива копируем в папку нашего проекта (естественно, без справки). В секцию uses проекта добавляем PngImage, и дело в шляпе. Теперь png-картинки грузятся без проблем, наравне с jpg и bmp. (Кстати, в Delphi 2009 TPNGImage уже включен, как стандартный).
"Рисунки GIF забыли!" - возопил мой внутренний голос, но заткнулся, когда в секцию uses я дописал: GifImg. Больше ничего и не нужно. Ибо в Delphi 2007 уже имеется поддержка gif.
Осталось решить, где лучше отображать картинку. Проще всего - справа от текста. При включенном режиме "Формат - Перенос по словам" текст и картинка совсем не мешают друг другу. На всякий случай, пусть нажатием Ctrl+K картинка скрывается / вновь показывается. Когда картинка скрыта - текст разворачивается на всю ширину окна. Для листания присобачим кнопки "взад-вперед" и, на всякий пожарный, "Удалить картинку" и "Удалить все". Дефолтные размеры окна у Demagog'a невелики и картинка будет похожа на большую почтовую марку, но это - дело поправимое. При изменении размеров окна программы, пропорционально поменяется размер картинки. Потихоньку, полегоньку... вот такая икебана:

- Эй-эй! А откуда взялся фоновый рисунок под текстом?! - спросите вы. Об этой мелочи как-нибудь потом.
С версии 4.16.210 двойной клик по панели изображений запустит обзор через Проводник Windows всех картинок к документу. Выбранная в окне обзора картинка будет показана с помощью внешней программы, ассоциированной с файлами изображений данного типа. По умолчанию - это стандартный вьюер Windows.

9. "Что могут словари..." Билингва и другие хитрости
| Выйду на поле в мятых трусах коричневых, | "Позвольте мне сделать одну |
| Знаю в футболе пару финтов гарринчевых1. | вещь для вас очень ясной..." |
| На деревяшке выжгу тебя паяльником, | |
| Скину рубашку, спрячусь под пододеяльником. | Ричарду Никсону однажды сказали: |
| I love you baby. | "Если не отучитесь повторять эту фразу |
| I just believe in what you say. | по двадцать раз за одно выступление, |
| Yes. It is table. And it was table yesterday. | то никогда не станете президентом!" |
| I love you baby. Baby, you love my "имидж". | |
| O-o. I am crazy. I can speak English! | |
| Пародия на песню А.Серова "Ты меня любишь" | |
| 1Гарринча - знаменитый бразильский футболист |
Р.Никсон стал-таки президентом. И отвык употреблять в речах навязчивую фразу. Но бывают случаи, когда повторы необходимы, например, при заучивании текста наизусть, или изучении иностранного языка. Здесь мы рассмотрим некоторые возможности, предоставляемые словарями типа REX.
А теперь
позвольте мне сделать одну вещь для вас очень ясной
.
Demagog, кроме словарей типа DIC, о которых подробно рассказано в предыдущих главах сей повести, "понимает", начиная с версии 3.10.142, корректировочные словари на основе так называемых регулярных выражений. Для этого в программу был включен свободно распространяемый модуль RegExpr.pas, разработанный Андреем В. Сорокиным. Я внес в него небольшую поправку, позволившую корректно обрабатывать с помощью регулярных выражений русскоязычные тексты.
Для таких словарей я придумал расширение .REX - от слов Regular Expressions. Кроме того, Rex означает "король" - король словарей, самое эффективное средство для предварительной обработки текста. Если одновременно подключены словари DIC и REX, то словарь REX применяется к тексту первым. Могут быть одновременно подключены несколько словарей одного типа, тогда они применяются к тексту в алфавитном порядке их имен.
REX-словари к Demagog'y подходят также и к Балаболке (и наоборот); ибо в настоящее время Балаболка использует для поддержки регулярных выражений тот же, аналогично модифицированный, модуль RegExpr, и применяет для словарей расширение .rex. (Ранее применяемое расширение .ini приводило к "откату" содержимого словарей при выполнении операции "Восстановление системы", т.к. Windows считает файлы .ini "своими", и включает их в список восстанавливаемых).
Если вы не знакомы с регулярными выражениями, то можете пропустить все, написанное дальше, кроме последнего параграфа, обозначенного тремя звездочками.
Задача 1. Заставить программу читать текст "по словам". Этого можно добиться, поставив в тексте точку после каждого слова. Сделать такое вручную для сколь-нибудь длинного текста - немыслимо.
Решение. Отдельное слово в тексте - это последовательность, состоящая из алфавитно-цифровых символов и знака подчеркивания (обозначаемых метасимволом \w). То есть:
\w+
где знак + указывает, что в слове должно быть не менее 1-го символа. Чтобы при поиске в тексте очередное слово запоминалось, добавим скобки:
(\w+)
и укажем, что найденное слово заменяется им же самим с точкой в конце:
(\w+)=$1.
Здесь $1 - это ссылка на запомненное значение скобочной группы номер 1, а она у нас всего одна и есть. Скобочные группы (...) принято называть подвыражениями. Demagog допускает до 15 подвыражений в одном правиле. Ссылки на подвыражения с номерами больше 9 надо записывать, заключая номер в фигурные скобки, например: ${10}
Задача 2. Читать каждое слово в тексте трижды.
Решение. (\w+)=$1 $1 $1
Задача 3. Читать каждую строку текста трижды.
Решение. Предполагая, что каждая строка, кроме слов может содержать также пробелы, знаки препинания, кавычки, тире, круглые и квадратные скобки и знак апострофа, и заканчиваться символами возврата каретки и перевода строки, запишем: ([\w\x20\.\,\!\?\:\"\-\(\)\[\]\']+\r\n)=$1$1$1
Перечень символов положено заключать в квадратные скобки, вот так: [...]+. Ну, а \x20 - это, разумеется, 16-ричный код символа "пробел".
Задача 4. Выделить (каким-либо образом) в тексте англоязычные фрагменты.
Решение. Уже не получится обозначать слово в тексте подвыражением (\w+) по той причине, что \w - это и русские и английские буквы, а также цифры и знак подчеркивания. А нам нужно отлавливать исключительно латиницу! Вот: ([A-z\.\,\!\?\-\'\"\(\)\[\]\_\x20]+)=<eng>$1</eng>
Любая найденная в тексте последовательность латинских букв, пробелов, знаков препинания, кавычек, круглых и квадратных скобок и апострофов будет выделена с обеих сторон мной самим придуманными тегами: <eng>...</eng>. Всё хорошо? Не тут-то было. Если русский текст содержит знаки препинания, то они тоже будут окружены тегами, например: Вперед<eng>!<eng>. Ведь знаки препинания перечислены в списке допустимых английских символов. Убьем лишние теги, заключающие в себе лишь знаки препинания, добавив второе правило: <eng>([\!\?\.\,\-\'\"\(\)\[\]\_\x20]+)</eng>=$1
В довершение, заменим условные теги настоящими, а именно, тегами SAPI5 смены голосового движка:
<eng>=<voice required="Name=Microsoft Mike">
</eng>=</voice>
Английский голос можно прописать любой, из установленных на компьютере. Бесплатные голоса Microsoft Sam, Microsoft Mike, Microsoft Mary работают под Windows XP; голос Microsoft Anna - под Windows 7. Выбрав для чтения текста какой-либо русский голос и подключив словарик из этих 4-х правил, мы услышим чтение текста, содержащего английские фрагменты, на два голоса! Послушать пример.
* * *
Итак, вот они, специальные словари: SpecREX.zip Архив содержит 4 словаря:
_По_словам.rex - чтение текста "по
словам".
_Слова_трижды.rex
- каждое слово текста читается 3 раза.
_Строки_трижды.rex
- каждая строка текста читается 3 раза.
А вот этот словарь позволяет читать английские фрагменты
текста заданным английским голосовым движком.
Я_Билингва_SAPI5.rex
Откорректируйте его для указания нужного английского движка.
Пояснения - в комментариях в тексте словаря.
Первые 3 словарика надо подключать только по одному.
Но любой из них можно комбинировать с билингвой. Обратите внимание на первые
символы в названиях словарей. Поскольку словари срабатывают в алфавитном порядке
их имен, то Билингва будет срабатывать в последнюю очередь - так и надо, иначе
возникнет ошибка.
Post Scriptum 1. Скептик скажет: "Билингва - это сложно, неуклюже и ненадежно! Да и русские голоса с английскими плохо сочетаются по громкости и тембру. А регулировать тегами - замучишься...". А я и не спорю, мне тоже хотелось бы, чтобы английские фрагменты текста читал тот же русский движок. А ежели он не может?! Научим.
Словарик Lat2Cyr.dic - это простейший "транслитер", переводящий латиницу в кириллический текст. Он - заведомо не полон и ждет энтузиастов, которые бы его усовершенствовали. Сейчас это - лишь "сухой остаток" от известного бесплатного словаря Michelangelo. Поскольку правила в Lat2Cyr.dic не содержат символов ударения, то он пригоден практически для любого русскоговорящего движка. This is a table -> Сзис ис э тэйбл!
Post Scriptum 2. "К вопросу об использовании клавишных духовых инструментов священнослужителями младшего и среднего звена на внецерковных праздничных мероприятиях", или "на хрена попу гармонь?" Если пользователь не желает слушать английские вставочки в тексте ни в правильном британском, ни в грубом транскрибированном виде, если они ничего не дают ни уму его, ни сердцу, то не проще ли их вообще игнорировать? Пожалуйста. Это сделает словарик KillLat.rex, состоящий всего из одной строчки:
[\(\"]*[A-z]+[\"\)\.\,\:\;\!\?]*=
Из текста будет удалена любая последовательность латинских букв, числом не менее одной, за которой, возможно, следуют знаки препинания.
10. Склонятор!
| Царь Александр III встретил на прогулке |
| спешащего по делам рабочего. |
| - Куда идешь, дурак? |
| - В депу, Ваше величество! |
| - Дурак, "депо" - не склоняется! |
| - Перед Вашим величеством всё склоняется! |
| - Хм! Держи рубль... умник! |
| Легенда. |
Составители словарей часто сетуют на необходимость выписывать все варианты одного и того же слова. Приходится перебирать по очереди падежные окончания для мужского, женского, среднего рода. А кроме существительных... есть еще глаголы, причастия, деепричастия... Кошмар!
Вот здесь лежит словарик формата REX, который каждое слово в ед. числе и именительном падеже заменяет на список всех его возможных словоформ. Насчет "всех возможных" - это я прихвастнул, но результат действительно впечатляет. Это - "альфа версия" словаря, кое-какие словоформы он пропускает, а некоторые типы слов обрабатывает некорректно. Начало, однако, положено!
(продолжение следует)
11. Криптография
Прежде
чем читать дальше, подумайте: нужно ли это вам и зачем?
Ведение шифрованной переписки очень быстро
заинтересует: 1) вашу жену; 2) сослуживцев; 3) начальство. А там и спецслужбы
подключаться. Доказывайте потом, что вы просто общались с симпатичной
длинноногой блондинкой...
Имейте в виду, что компьютер является источником электромагнитного излучения, и все что вы набираете на клавиатуре и то, что видно на мониторе, может быть дистанционно перехвачено с помощью специального оборудования. И никакие шифровки не помогут. Поэтому скрывать надо сам факт наличия секретного текста. "Неуловимого Джо" никто не поймал, потому что он никому не нужен. Оттого, что нигде не засветился.
Предлагаемая Demagog'ом система защиты информации состоит в следующем. Любой текст можно сохранить как криптограмму - тоже текстовый файл, но с расширением: .~
При этом ничего, казалось бы, не происходит. Файл по-прежнему можно редактировать, прослушивать и т.п. Но открыв его любой другой программой, вы обнаружите бессмысленный набор символов. Вот как это работает:
Отправка сообщения. Войдите в меню "Сервис - Общие настройки... - Пароль для криптограмм". Не ставьте галочку "Сохранять", если к компьютеру имеете доступ не только вы. Наберите нужный текст. Сохраните его, как криптограмму. Отправьте получателю, сообщив, вместе с тем и пароль.
Не используйте короткие и/или очевидные пароли. Не используйте один и тот же пароль длительное время. ВНИМАНИЕ! По умолчанию в Demagog'e установлен (в демонстрационных целях) автоматически генерируемый неизвестный пароль. Закодированные на его основе тексты сможет прочесть любой пользователь Demagog'a.
Прием сообщения. Откройте полученный файл, как криптограмму. Если нужный пароль еще не введен, то увидите абракадабру. Перейдите в меню "Сервис", как описано выше и укажите пароль. Затем заново откройте файл через меню "Файл - Недавние".
Если постоянно используется один и тот же пароль и для него стоит галочка "Сохранять", то вышеописанные "танцы с бубнами" не нужны. Криптограммы сразу будут открываться в читабельном виде. Но тогда посадите большую злую собаку охранять подходы к вашему компьютеру.
Заключение
Замечание, между прочим...
![]() |
На Demagog'a в Инете уже достаточно ссылок, в основном они ведут ко мне на страницу или на вышеупомянутый Софт-Мэйл-ру. Но есть и отдельно размещенные копии. Не поведитесь на прикольную картинку и не скачивайте с anyfiles.ru - файл Demagog.rar имеет там непомерный размер в 5.3 мб и бесплатная закачка обязательно оборвется, не дойдя до конца. А за "ускоренную супернадежную" с Вас попросят денег. В частично скачанный архив мне удалось заглянуть: там лежит в точности мой проект... плюс файл размером 5 мб - "Голубой вагон.mp3". Аналогичная ситуация с windsoft.ru. Архив в 6 мб, зазывно названный "Demagog 2011" содержат старую версию 2009 года + рекламу очередной интернет-пирамиды и несколько фоток голозадых девок. Катаюсь по полу от смеха. А заодно, напоминаю: Братья и сёстры во Инете! Истинный дистрибутив Demagog'a ИМЕЕТ РАЗМЕР ВСЕГО В ДВА МЕГАБАЙТА и скачивать его нужно только с моей страницы: http://aloys.narod.ru/Demagog.zip |
Что говорят
История версий