Говорящий текстовый редактор
 
 

Locations of Site Visitors Версия 7.28.326

Полная поддержка юникода, многоязыяный интерфейс.
Full Unicode support, multi-language interface.

История версий

Поддержать сайт - Donate

В дистрибутив включены исходные коды библиотек: для поддержки регулярных выражений; и для встроенного интерпретатора. Библиотеки лицензированы под MPL 2.0.
The distribution includes source code: SkRegExp to support regular expressions; and VerySimpleLua to support built-in interpreter. These libraries are licensed under the MPL 2.0.

Говорящий текстовый редактор

© Benedict Lee n1d3@yahoo.com arnys@mail.ru



Введение
  1. SAPI4 и Николай Еланович Дигало
  2. SAPI5, три грации и старый друг
  3. Нормальные герои... или повесть об алгоритме словарных замен
  4. Нормальные герои, продолжение... или нет предела совершенству
  5. Свежий взгляд
  6. "Глокая куздра", "четыре четырки" и Питон
  7. "Говорит и показывает..."
  8. "Что могут словари..." Билингва и другие хитрости
  9. Склонятор!
10. Калькулятор
  11. Вызов программы из командной строки
  12. Подсветка ключевых слов в компоненте RichEdit
  13. Как добавить в программу новый язык интерфейса?
  14. Путь самурая. Demagog в мире Юникода
  15. "Брюки превращаются..." или что такое "фонетический алфавит"?
  16. Формат DXT - "документ Demagog"
  17. Извлечь шляпу из кролика... или текст любой ценой
  Заключение

Введение

   Но этот меч, который я даю вам в руки,
   есть лучший из всех мечей, что я раньше сделал.
   Для этой цели удача посетила меня. 
   Я сделал это из философских соображений... 
 
   Оружейник Хаттори Хансо

   Demagog - это текстовый редактор, который может прочесть вслух загруженный в него текст или записать его в виде аудио-файла. Вот, кратко, его возможности. Полная поддержка Юникода. Чтение текста вслух. Конвертация текста в аудио-файл. Пакетная запись аудио. Запись аудио в виде сериала, т.е. с делением на фрагменты заданного размера. Поддержка словарей корректировки произношения популярного формата DIC. Поддержка аналогичных словарей формата REX, основанных на регулярных выражениях. Импорт рисунков из документов MS Word и E-Book. Развитая система поиска и замены в тексте. Подсветка орфографических ошибок, омографов, и близко стоящих похожих слов (опция "Свежий взгляд"). Пользовательские настройки окна редактирования: шрифт, фон или фоновая картинка. Встроенный интерпретатор для создания пользовательских скриптов: например, экспресс-анализа текстов или математических расчетов.

    Первой опубликованной в Инете была версия 1.08.020 beta, еще не имевшая всех нынешних функциональных возможностей. 28 октября 2007 года - день рождения программы Demagog.

   Фрагменты исходного текста Demagog'a были использованы разработчиками погодного робота Meteonova, созданного под руководством кандидата географических наук Александра Королькова.

   В 2009 г. Demagog занял 3-е место в конкурсе Soft.Mail.ru "Самые популярные программы года" в номинации "Текст".

    Одно из авторитетнейших компьютерных изданий - выходящий на 15 языках журнал "CHIP" (№5/2014), назвал Demagog'a в числе наиболее известных программ для управления речевыми движками.

    Издание на Google books: "250 лучших бесплатных программ" так же включило Demagog'a в свой список, раздел "Преобразование текста в звук".

    Ссылку на Demagog'a можно обнаружить на множестве интернет-ресурсов, однако новые версии надо скачивать только с этой моей странички.

Demagog.zip Дистрибутив программы. Для установки достаточно распаковать zip-архив в какую-либо папку на вашем компьютере.
xdoc2txt.zip Консольный конвертер PDF, Word, Excel, OpenDocument,... --> TXT.  Документация прилагается. Поместите xdoc2txt.exe в рабочую папку Demagog'a и в диалоге открытия файлов станут доступны дополнительно форматы: Adobe PDF, Excel, OpenDocument, MS PowerPoint. Подробнее>>
RU-YO-orfo.zip Значительно более полный вариант русской орфотаблицы. В отличие от поставляемой с дистрибутивом, эта орфотаблица содержит и варианты с буквой "ё".
NICOLAI Русский голосовой движок Elan Nicolai, в просторечии - "Николай". Давно устарел и больше не поддерживается разработчиком. Но всё еще популярен в  кругу фанатов. Выгодно отличается от более современных голосов размером дистрибутива, всего 11 Mb. Работает под SAPI4 и SAPI5.
SAPI4 В ОС Windows, начиная с версии XP и выше - по умолчанию установлена голосовая ситема SAPI5. Если хотите, здесь вы можете дополнительно скачать SAPI4. Голосовые системы SAPI4 и SAPI5 не замечают друг друга и могут работать на одном компьютере.
DemagogSimpleDIC.zip
Словарь для движка "Николай": DemagogSimple.dic (около 10000 правил). Никаких гарантий, что он не содержат ошибочных или излишних правил, не дается.
Словарь "Микеланджело" Словарь для движка "Николай". Свыше 37700 правил. Никаких гарантий, что он не содержит ошибочных или излишних правил, не дается.
Замечание о словарях для движка Николай Словари *.dic для Николая, созданные некогда для SAPI4, работают в Demagog'e и под SAPI5, при условии, что в "Сервис - Общие настройки... - Чтение" стоит галочка "Игнорировать теги SAPI5". Тогда символы < > в словаре воспринимаются правильно: как знаки ударения.
Lat2Cyr.zip Словарь "транслитер" для преобразования латиницы в кириллицу.
Bilingva.zip Словарик для чтения двуязычного русско-английского текста! Он вставляет в текст теги смены голосового движка. И, будучи подключенным вместе с каким-либо другим REX-словарем, делает замены в тексте в последнюю очередь. Не зря у него такое алфавитно-последнее имя: Я_Билингва_SAPI5.rex
YOhmg.zip Экспериментальный словарик для разрешениея омографа ВСЕ/ВСЁ. Правильность работы словаря ~ 94%. А ошибки распределяются так: в 1% случаев ё ставится там, где не надо, и в 5% случаев не ставится там, где надо :)
opusenc.zip Неплохой аудио-конвертер, по мнению его разработчиков - лучший из всех. Он не входит в дистрибутив Demagog'a, но может быть помещен в его рабочий каталог и подключен через меню "Сервис - Общие настройки... - Аудио - Custom Encoder". Командную строку пользователь указывает вручную, она будет запомнена в настройках. Что-то вроде: opusenc.exe --bitrate 48 %1 %2 . Символы %1 и %2 - это условные имена входного и выходного аудиофайлов; реальные имена сгенерирует и подставит в командную строку сам Demagog. Тип выходного файла надо бы указывать "родной": opus, но подойдет и ogg. Тогда полученное аудио будет распознаваться и проигрываться Winows Media Player'ом.
fastencc.zip Аудио-конвертер в mp3, более быстрый, чем lame. Руководство пользователя - в архиве. Пример вызова как "Custom Encoder": fastencc.exe %1 %2 -br 48000
flac.zip Аудио-конвертер в звуковой формат flac. Версии для win32-64. Руководство пользователя - в архиве. Пример вызова как "Custom Encoder": flac.exe %1 -o %2
Source.zip Исходный код одной из ранних версий Demagog'a.

<<

1. SAPI4 и Николай Еланович Дигало

   Многие слышали об их существовании, а кое-кто даже ими пользуется. Программы-читалки текстов, берегущие наши глаза. "TextAloud", "Speaking Notepad", "Балаболка", уже полузабытая знаменитая "Говорилка"..., и другие. Считается, что создать нечто подобное - это высший программистский пилотаж. На самом деле - ничего такого сложного Здесь я опишу упражнение на языке Delphi, дающее вполне удовлетворительный результат. Тестировалось под ОС Windows 98, NT, 2000, XP, Vista, 7, 8, 10. Как это смотрится под "десяткой" вы уже видели.

    Всплывающие подсказки под каждой кнопкой объясняют их назначение, при этом в правой части строки состояния внизу дается развернутая подсказка. Когда курсор мыши находится над текстом, в строке состояния показывается размер текстового файла. Остальные данные в строоке состояния, по порядку: позиция текстового курсора; код символа за курсорм (в данном случае - это пробел); название файла показываемой картинки и их количество; коэффициент увеличения размера текста, задаваемый вращением колесика мыши.

    У программы многоязычный интерфейс. Его описание содержится в файлах типа *.ln. Добавив новый файл "языкового ресурса", мы, тем самым, добавим новый язык в меню.

    Итак, начнем с начала. Задача "синтеза речи", т.е. превращение электронного текста в звук давно решена средствами Windows. В Win 98, NT, 2000 установлен т.н. "менеджер голосовых функций" - Speech API версии 4.0. Сокращенно: SAPI4. В Win XP, Vista, 7, 8, 10 - SAPI5. Эти голосовые системы абсолютно не совместимы, но друг другу не мешают и могут сосуществовать на одном компьютере.

   Далее. Чтобы компьютер заговорил, на нем должна быть установлена хоть одна Text To Speech Engine. В переводе на русский: "голосовой движок". Остается соорудить программную оболочку, для распознавания имеющихся на компьютере голосовых движков, загрузки текстового файла и передачи его выбранному движку для чтения вслух!

   Для работы в режиме SAPI4 Demagog использует соответствующий низкоуровневый (COM) интерфейс. Очень ясно (с примерами и без лишних деталей) необходимые функции SAPI4 описаны в статьях Брайана Лонга (для тех, кто читает на английском) и в книге Дениса Буторина "MS Agent и Speech API для Delphi". Первую половину книжки, про MS Agent'a (создание мультяшных "помощников") смело пропускаем. Дальше читаем внимательно. Поэкспериментируйте с демо-проектами с прилагаемого к книге CD. Стараться понять до конца, как это работает, не нужно, главное - усвоить последовательность, в какой должны объявляться TTS-интерфейсы. Для хранения текста используется компонент RichEdit. Кнопки добавляются "по вкусу". Я использовал компоненты ActionList и ImageList для централизованного построения графического интерфейса.

     Наиболее популярным русским голосовым движком под SAPI4 был Nicolai, разработанный французской компанией Elan (позже сменившей название на Acapela). Он давно устарел и больше не поддерживается разработчиком, но все еще популярен у фанатов. Его последнюю версию Elan Nicolai 5.1 до сих пор можно найти на просторах Инета. Отмечу, что эта версия работает и под SAPI5.

   При написании Demagog'a я придерживался принципа "минимализма". Классическое "выпадающее" меню и кнопки для типичных действий, объединенные в основную и дополнительную "панели инструментов". Наличествуют стандартные функции текстового редактора, включая развитую (и очень шуструю) систему поиска/замены в тексте; а также приведение текста к аккуратному "литературному" виду.

    Помимо этого, Demagog понимает и автоматически преобразует в ANSI (кириллица Windows) старые кодировки: DOS (из уважения к DOS) и KOI8-R (из уважения к Максиму Мошкову).

   Demagog поддерживает словари корректировки произношения популярного формата DIC, а также словари формата REX на основе регулярных выражений.

   Вместо чтения вслух Demagog может ускоренно записать аудио-файл типа WAV, MP3, OGG, WMA или MP4; звук при этом не слышен. Для конвертации WAV в другие форматы Demagog вызывает соответствующие внешние программы, они входят в установочный комплект, поскольку бесплатные и свободно распространяемые. Пользователь может настроить вызов любой другой внешней программы конвертации, допускающей запуск из командной строки.

   Поддерживается импорт рисунков из открываемых документов MS Word (doc, docx, rtf) и электронных книг: Fiction Book (fb2), Electronic Publication (epub).

    Ранние версии с поддержкой одного только SAPI4 обошлись без использования сторонних компонентов и прекрасно скомпилировались на Turbo Delphi 2006 Explorer.

<<

2. SAPI5, три грации и старый друг

   С распространением Windows XP, а затем Windows 7 и т.д. разработчики говорящих программ отложили в сторону книгу Дениса Буторина, и взялись за статьи Брайана Лонга, в которых рассказано, как заставить Delphi понимать SAPI5. В Сети можно найти и другие, аналогичные, учебные примеры. 

   Для поддержки SAPI5 Demagog использует компоненты, импортируемые из Microsoft Speech Object Library, входящей в состав Windows. Для Win 7 и выше, номер версии библиотеки - 5.4.

   "Component - 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" с новыми компонентами!

   Продолжим читать дальше статью Б.Лонга - теперь приведенные в ней примеры будут успешно компилироваться.

   Для 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, хочешь под 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 Да ($Дантес=Дант^ес | смотрите=смотр^ите | тартан*=тарт^ан | выстрел*=в^ыстрел)
MS Irina (входит в состав Windows 10) MK-Irina.mp3 Да (губам=гъубам | смотрите=сматрите | отдаленного=отдалённого | пушечного=пушичного)
MS Pavel (входит в состав Windows 10) MK-Pavel.mp3 Да (губам=гъубам | смотрите=сматрите | отдаленного=отдалённого | пушечного=пушичного)
IVONA Tatyana MK-Tatyana.mp3 Да (отдаленного=отдалённого)
IVONA Maxim MK-Maxim.mp3 Да (смотрите=сматрите | отдаленного=отдалённого)

   Теперь начинаем творить собственную читалку под SAPI5. Правда вы (а также я) - не первые. Нас, братцы мои, опередили! Гляньте сюда. Двуязычный синтезатор речи EXO Игоря Паламара, на основе статьи Брайана Лонга. Прилагаются исходные тексты программы и сама статья. Кстати, полезное упражнение: удалить из EXO все лишнее, оставив работу только с одним языком. (Зачем двойной набор одинаковых функций чтения русских и английских фрагментов текста, когда переключение голосов с русского на английский можно обеспечить расстановкой в тексте управляющих тегов). Обратите еще внимание, как в EXO реализовано блочное чтение теста. Поучительно, не правда ли?

   Итак, Demagog отныне поддерживает SAPI5, благо было, на чей опыт опереться. Конечно, я не списывал все буквально у Брайана Лонга. К примеру, он (а вслед за ним автор EXO) употребили для останова чтения команду SpVoice.Skip('Sentence',MaxInt), что привело к большим неприятностям с некоторыми движками (см. выше). Вот как правильно: SpVoice.Speak('',SVSFPurgeBeforeSpeak).

   Замечу, что для компиляции проекта уже не получится использовать Turbo Delphi 2006, где отключена опция импорта компонентов.

<<

3. Нормальные герои... или повесть об алгоритме словарных замен

   Ходы кривые роет подземный умный крот.
   Нормальные герои всегда идут в обход!
   Глупцы, героев строя, бросаются вперед.
   Нормальные герои - всегда наоборот.
   В обход идти, понятно, не очень-то легко.
   Не очень-то приятно и очень далеко.
   Зато так поступают одни лишь мудрецы,
   Зато так наступают одни лишь храбрецы.
   И мы с пути кривого ни разу не свернем!
   А, надо будет - снова пойдем кривым путем!
  
   Песенка из кинофильма "Айболит-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. Нормальные герои, продолжение... или нет предела совершенству

"Смотрите сюда... Это основная схема... Это просто, как дважды два.
Чистая случайность, что это до сих пор не было построено"
 
Инженер Гарин

    Во-первых, не откладывая в долгий ящик, устраним в нашем алгоритме одно слабое место. Вы, конечно, его заметили. Нет? Смотрите сюда. Допустим, в словаре есть 2 правила, расположенные в следующем порядке:
 
*ащенн*=ащённ
...
*враще*=враще<

    Как будет выглядеть измененное слово"возвращенный"? При прямом переборе правил получим верный результат: возвращённый. Ибо правила с одинаковой длиной левых частей выполняются в порядке их следования в словаре. А вот как работает наш алгоритм. В хеш-таблице образуется два словарных гнезда:
  
*ащенн*|*ащенн*=ащённ
...
*враще*|*враще*=враще<

    Их местоположение в хеш-таблице и порядок следования заранее неизвестны, да и не имеют значения. И вот какое гнездо будет выбрано при проверке упомянутого слова. СмотрИте: 
  
возвращенный
...
возвр
озвра
звращ
враще
ращен
ащенн
...

    Результатом будет: возвраще<нный. Выбор словарных гнезд происходит в том порядке, в каком генерируются ключи поиска процедурой Trunks! И как бы мы не переставляли местами сии 2 правила в словаре - итог будет один и тот же. Неутешительный. Потому что в "быстром алгоритме" в нужном порядке проверяются лишь правила, сидящие в одном словарном гнезде. А пока не сгенерирован следующий ключ, мы даже не знаем о существовании (или не существовании) очередного словарного гнезда. И не сможем понять, что текущая замена - преждевременна и делать ее не надо. Ибо найдется лучшая.

    Это - ложка дегтя в бочке меда "быстрого алгоритма". Частично пересекающиеся правила ложатся в разные словарные гнезда (при том, что могут подходить к одному и тому же слову!) и мы имеем то, что имеем... Где-то так 1 раз на 1000. Но для больших текстов - вполне может быть. Для нашего алгоритма решением было бы: взять, да переделать проблемные правила, ибо нехорошо, когда одно правило является, по сути, продолжением другого. Разумеется, ни вы, ни я и никто другой этим заниматься не будет.

    Поэтому, видоизменим алгоритм. Во-первых, генерируя для очередного слова список всех его огрызков, включаем лишь те огрызки, которые уже присутствуют в хеш-таблице. Отсюда: размер списка "подходящих огрызков" сократится в 10..20 раз. Это - очень важное достижение, как будет ясно из дальнейшего. Во-вторых, пройдясь по списку огрызков, выберем в хеш-таблице все подходящие словарные гнезда и объединим их в общий список правил, потенциально подходящих к данному слову! Отсортируем его в порядке убывания длин левых частей правил, используя сортировку Хоара. (Т.н. QuckSort-алгоритм). И только после этого начнем применять правила из этого списка к данному слову (словосочетанию).

    Некоторые технические детали. Как придать QuckSort устойчивость, чтобы не перставлялись местами "равные" элементы? При формировании хеш-таблицы, каждому правилу сопоставим целое 9-значное число: 3 знака - длина левой части правила; 6 знаков - инверсная позиция этого правила в исходном словаре. Т.е. для правила в строке 15372 это будет 999999 - 15372 = 984627. Если длина левой части правила, например, 16, то имеем: 016984627. Сортировка общего списка в классическом алфавитном порядке(!) расположит все правила в порядке возрастания длин их левых частей, при этом для одинаковых длин порядок правил останется таким же, как в исходном словаре. Проверка по сортированному общему списку правил ведется от его конца к началу.

    Почему не наоборот? Инвертировать длину правила, а номер его в словаре оставлять неизменным? И сортировать в алфавитном порядке, чтобы потом перебирать сортированный общий список с начала до конца?

    В первом способе QuckSort выполняется примерно на 30% быстрее. 

    Кстати, тот факт, что изначально общий список частично отсортирован (в пределах вошедших в него словарных гнезд), дает выигрыш по скорости еще ~10%.

    Во-вторых, сейчас мы сделаем то, до чего никто не додумался раньше. Как было сказано, в словарях формата 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-й проход - применено правило постановки ударения
корреспондент*=корреспонде<нт

    Итак, по-прежнему используя лишь стандартные средства Delphi, мы получили ново-классический алгоритм словарных замен:

1) Проверка ведется по словарю в целом;

2) Правила применяются в порядке убывания длин их левых частей. Управляющие символы * и $ в подсчет длины не входят. Примеры: лиса - 4; вьюжн* - 5; $ПВО - 3; $*O* - 1; *u* - 1; $* - 0; * - 0; и т.д. и т.п.;

3) Правила с одинаковой длиной левых частей применяются в том порядке, в каком стоят в словаре;

4) Сохранены все нововведения "быстрого алгоритма" касательно звездочек внутри левых частей правил. Наподобие: ворот* города=воро<т го<рода | все * *ло=всё ло | * * *=три звезды;

5) В отличие от традиционной практики, правила применяются к тексту не однократной проверкой по словарю, а до тех пор, пока возможно.

    Скорость его работы составляет в среднем 3/4 от "быстрого алгоритма". Это ведь не шутка, проверяя очередное слово, каждый раз составлять и сортировать единый список подходящих правил. Зато отсутствует отмеченный выше недостаток, проявлявшийся в "слишком раннем" выборе правил.

    Совпадение результатов классического и ново-классического алгоритмов составляет 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.

   Видим, что "сходство", вообще говоря, не транзитивно. Поменяв порядок сравнения, можно получить иной результат. Чтобы побороть такой эффект, будем вычислять "коэффициент сходства", усредненный по обоим словам. Общее число совпадающих подстрок разделим на общее число подстрок: (3+5)/(12+18) = 0.267

   Этот, т.н. "алгоритм нечеткого сравнения строк" предложен в 1998 г. Владимиром Кива. На практике оказывается, что слова с уровнем сходства 0.35..0.50 зрительно и по звучанию уже весьма похожи!

   Конечно, повторы в художественных текстах - совсем не обязательно признак неопытности автора. Зачастую они привносят в произведение дополнительную смысловую и эмоциональную составляющую. Поэтому, не станем объявлять графоманом великого писателя земли русской.

   "В это время в гостиную вошло новое лицо. Новое лицо это был молодой князь Андрей Болконский, муж маленькой княгини. Князь Болконский был небольшого роста, весьма красивый молодой человек с определенными и сухими чертами. Все в его фигуре, начиная от усталого, скучающего взгляда до тихого мерного шага, представляло самую резкую противоположность с его маленькою, оживленною женой. Ему, видимо, все бывшие в гостиной не только были знакомы, но уж надоели ему так, что и смотреть на них и слушать их ему было очень скучно. Из всех же прискучивших ему лиц, лицо его хорошенькой жены, казалось, больше всех ему надоело..."

<<

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. "Говорит и показывает..."

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

   Похожая история вышла и с моими принципами. Нет-нет, дело не во внезапном приступе жадности; 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.

   Осталось решить, где лучше отображать картинки. Проще всего - в специальной Галерее, справа от текста. Отступ Галереи от левого края в процентах задается в настройках. Если указать 50%, то тексту и картинкам достанется места поровну. По умолчанию: 65%. Для листания присобачим кнопки "взад-вперед" и, на всякий пожарный, "Удалить картинку" и "Удалить все". Дефолтные размеры окна у Demagog'a невелики и картинка будет похожа на большую почтовую марку, но это - дело поправимое. При изменении размеров окна программы, пропорционально поменяется размер картинки. Потихоньку, полегоньку... вот такая икебана:

 

    - Эй-эй! А откуда взялся фоновый рисунок под текстом?! - спросите вы. Об этой мелочи как-нибудь потом.

  <<

8. "Что могут словари..." Билингва и другие хитрости

   Выйду на поле в мятых трусах коричневых, "Позвольте мне сделать одну
   Знаю в футболе пару финтов гарринчевых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, корректировочные словари на основе так называемых регулярных выражений.

   Для таких словарей я придумал расширение .REX - от слов Regular Expressions. Кроме того, Rex означает "король" - король словарей, самое эффективное средство для предварительной обработки текста. Если одновременно подключены словари DIC и REX, то словарь REX применяется к тексту первым. Могут быть одновременно подключены несколько словарей одного типа, тогда они применяются к тексту в алфавитном порядке их имен.

   Если вы не знакомы с регулярными выражениями, то можете пропустить все, написанное дальше, кроме последнего параграфа, обозначенного тремя звездочками.

   Задача 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]+[\"\)\.\,\:\;\!\?]*=

   Из текста будет удалена любая последовательность латинских букв, числом не менее одной, за которой, возможно, следуют знаки препинания.

<<

9. Склонятор!

   Царь Александр III встретил на прогулке
   спешащего по делам рабочего.
   - Куда идешь, дурак?
   - В депу, Ваше величество!
   - Дурак, "депо" - не склоняется!
   - Перед Вашим величеством всё склоняется!
   - Хм! Держи рубль... умник!
 
   Легенда

    Составители словарей часто сетуют на необходимость выписывать все варианты одного и того же слова. Приходится перебирать по очереди падежные окончания для мужского, женского, среднего рода. А кроме существительных... есть еще глаголы, причастия, деепричастия... Кошмар!

    Вот здесь лежит словарик формата REX, который каждое слово в ед. числе и именительном падеже заменяет на список всех его возможных словоформ. Насчет "всех возможных" - это я прихвастнул, но результат действительно впечатляет. Это - "альфа версия"  словаря, кое-какие словоформы он пропускает, а некоторые типы слов обрабатывает некорректно. Начало, однако, положено!

(продолжение следует)

<<

10. Калькулятор

   К вопросу о целесообразности    На хрена попу гармонь?
   использования клавишных духовых   
   инструментов священнослужителями    Пословица
   младшего и среднего звена на  
   внецерковных праздничных мероприятиях.  
   
   Тема для диссертации  

    Арифметико-алгебраический... Что мы имеем на данный момент? Программу, наделеннную помимо стандартных функций текстового редактора, умением читать текст вслух! Могущую записать для вас аудиокнигу! А также, проверить орфографию текста! И, при том, неспособную ответить на вопрос: "Сколько будет дважды два?" Или: "Какой налог должна была заплатить телеведущая К.Собчак с найденных у нее в сейфе полутора миллионов евро?"

    Это было странно. Но теперь сей пробел среди многочисленных талантов Demagog'a - устранен.

     Пусть текст в окне представляет собой набор арифметических выражений, записанных в отдельных строках или в одной строке через точку с запятой. Тогда по нажатию клавиши F2 в окне статистики будет показан результат вычислений. Например:'Контрольный пример'; ''; 12^2; 1/3+1/6; (12+0.5)*11/4-3 . Результат:     

Контрольный пример
 
144
0.5
31.375

    Разрешается вставлять поясняющий текст, заключенный в апострофы, он будет распечатан вместе с результатами вычислений. Каждый результат выводится в отдельную строку. Если в тексте выделен фрагмент, то расчет выполняется только для содержимого этого фрагмента с подстановкой результа. Например, при написании делового письма, вы можете, по ходу дела, производить подсчеты прямо в тексте документа.

     Доступны операции сложения, вычитания, умножения, деления, взятия остатка от деления, возведения в степень:  +   -   *   /   %   ^

    Доступны элементарные математические функции: sin, cos, tan, atan, asin, acos, rad - перевод градусов в радианы, deg - перевод радианов в градусы, ln - натуральный логарифм, log - десятичный логарифм, exp - экспонента, sqrt - квадратный корень, abs - абсолютная величина числа, max - максимум из нескольких чисел, min - минимум из нескольких чисел, floor - округление до целого в меньшую сторону, ceil- округление до целого в большую сторону.

     ...И программируемый! Я не шучу. Demagog умеет выполнять  вычисления по заранее заданным в текстовом файле командам. Такой текст, содержащий только команды и комментарии к ним, называется скрипт. Как для упомянутых элементарных вычислений, так и для выполнения скриптов в Demagog'e используется свободно распространяемый интерпретатор языка программирования Lua.

    В настоящее время Lua широко используется в проектах, где нужен простой и мощный встраиваемый скриптовый язык. Например, в программировании игр. Поскольку Demagog,  в какой-то мере - тоже игрушка, нуждающаяся в расширении ее возможностей, то и здесь Lua пришелся к месту. Вот, хотя бы, такая история...

    Проверка гипотезы об авторском инварианте русских литературных текстов. Однажды, дождливой весенней порою, в Инете нашел я престраннейший факт. Открытье великое прямо, не скрою, но что-то смотрелось в нем как-то не так. Его открывали, не зная покоя, семь лет пролетели, как миг, без следа. Причиной тому было время такое - компьютеров не было в мире тогда!

    Итак, как можно узнать, пройдя по указанной ссылке: доля служебных слов в тексте, т.е. предлогов, союзов и частиц - это важный показатель. Предполагалось, что он есть величина неизменная для каждого конкретного писателя! Т.н. "авторский инвариант" (АИ). Из равенства (сильной близости) АИ для двух текстов, конечно, не следует, что у них один автор. Но заметное различие в АИ должно, как ожидалось, указывать на разных авторов. И даже помогать в определении плагиата.

    Исследование это проводилось в докомпьютерную эпоху и заняло годы: с 1974 по 1981. Подсчеты выполнялись вручную по равномерной выборке в 16000 знаков из каждого текста. Нынче же для определения доли служебных слов во всём тексте, требуется лишь несколько секунд.

    Запускаем Demagog. Из папки _Tests_ в дистрибутиве Demagog'a загружаем скрипт DemagogScriptTest6.txt в любую вкладку, кроме "0 - Статистика". Нажимаем клавишу F2. Появится диалог для выбора файла произведения того или иного автора. Годятся любые форматы, распознаваемые Demagog'ом. Текст будет загружен во вкладку статистики, проанализирован, и молча уберется нафиг, уступив место результату.     

    Довольно быстро выяснится, что АИ, на самом деле, не является постоянной величиной для одного и того же автора. Извольте посмотреть:

No Автор Год написания Текст АИ (%)
1 И.Ефремов 1946 Звездные корабли 19.307
2 И.Ефремов 1956 Туманность Андромеды 18,673
3 И.Ефремов 1963 Лезвие бритвы 21,378
4 И.Ефремов 1968 Час быка 20,240
5 И.Ефремов 1972 Таис Афинская 20.708
6 М.Горький 1913 Детство 20.185
7 М.Горький 1924-36 Книга о русских людях 21.354
8 М.Горький 1925-36 Жизнь Клима Самгина 20.253
9 Л.Соловьев 1940 Возмутитель спокойствия 21.044
10 Л.Соловьев 1956 Очарованный принц 21.632
11 Ф.Достоевский 1845 Бедные люди 25.043
12 Ф.Достоевский 1866 Преступление и наказание 25.961
13 Ф.Достоевский 1880 Братья Карамазовы 26.350
14 А.Пушкин 1830 Барышня-крестьянка 22.786
15 А.Пушкин 1836 Капитанская дочка 21.578
16 Г.Мартынов 1957 Каллисто 20.969
17 Г.Мартынов 1963-71 Гианэя 22.504
18 Г.Мартынов 1976-79 Сто одиннадцатый 23.999

    Не думаю, что этот список надо продолжать. Утверждение о постоянстве АИ с точностью до десятых долей - очевидным образом неверно. Для первого же, наугад взятого автора (Ефремов), доля служебных слов в разных его произведених может, как видим, отличаться почти на 3%.

    В упомянутом выше исследовании имеется приложение. Следуя ему, я заставил Demagog'a подсчитать АИ для неких четырех текстов. Доверяй, но проверяй, как говорится. Результаты представлены ниже.

No Год написания Текст АИ (%) - Demagog, расчет по всему тексту АИ (%) - исследование 1974-81, расчет вручную по выборке в 16 тыс. знаков
1 1926 Донские рассказы, сборник 22.874 22.46
2 1927 Тихий Дон, книги 1,2 18,700 19.55
3 1929-39 Тихий Дон, книги 3,4 21,079 22.69
4 1939-59 Поднятая целина 22,928 23.07

    Наблюдается неплохое согласие с цифрами, полученными исследователями сорок лет назад. Но, в силу отмеченной нами ошибочности гипотезы об "авторском инварианте", этого не достаточно, чтобы усомниться в М.Шолохове, как авторе "Тихого Дона".

 <<

11. Вызов программы из командной строки

    Все очень просто: Demagog.exe имя_файла список_параметров Список параметров - необязателен. Параметры в списке разделяются пробелами  и могут следовать в любом порядке. Их значения следующие:

/m - запустить программу свернутой в значок 
/r - открыть файл и начать чтение вслух
/s - открыть файл и сохранить текст в виде аудиофайла
/a - открыть файл и выполнить его, как скрипт
/c - прочесть вслух текст из буфера обмена
/q - закрыть программу после окончания чтения

Например: Demagog "C:\Tests\Некий текст.txt" /m /r /q

<<

12. Подсветка ключевых слов в компоненте RichEdit

(Или снова о проверке орфографии)

    Этот раздел посвящен вопросу, который рано или поздно, задает себе каждый, программирующий на Delphi. "У меня есть некий список слов, которые при отображении текста компонентом RichEdit должны выделяться цветом. КАК ЭТО СДЕЛАТЬ?!"

    Например, хорошо бы подсвечивать в тексте орфографические ошибки. А то Demagog может лихо проверить хоть целую книжку, выдавши список ошибок и... ищи-свищи их по всему тексту. Неудобно. Выделение (по желанию пользователя) неправильных слов цветом было бы очень полезно.

    Требуется решить проблему с минимальными усилиями, используя стандартные возможности компонента RichEdit. Решение очевидно: выделить нужное слово и через SelAttributes.Color поменять цвет выделенного. Затем снять выделение. И т.д. бегом по тексту, пока все нужные слова не будут найдены и раскрашены. Очень просто, не так ли?

    Но... вот как комментируют этот алгоритм в сборнике DRKB: Все способы подкраски синтаксиса реализованные через RichEdit грешат одним существенным недостатком - они реализованы через изменение атрибутов текста. И чем это грозит? А представьте себе что вы загрузили файл Дельфи, большой такой на пару мегабайт, например интерфейс от какого-то ActiveX от MS Word... и решили написать комментарий в начале файла, открываете скобку "(*" и ... ждёте секунд 10, а то и минуту пока изменятся атрибуты у всего файла, затем закрываете скобку "*)" и ждёте следующие пол минуты... Если же текст побольше, например вы загрузили какой-нибудь XML мегабайт на 50, то тогда после каждого нажатия клавиши у вас будет время выпить пивка и пройти уровень в Quake (желательно на другой машине, чтоб не тормозила)...

    Далее автор комментария объявляет саму идею порочной, советует обрабатывать за один раз только фрагмент текста, видимый на экране, и изобрести собственную процедуру прорисовки раскрашенного текста в окне, что технически сложно, и вообще не изобретайте велосипед, а используйте вместо RichEdit сторонний компонент SynEdit.

    Почесав в затылке и погуляв по разным форумам в поисках свежих идей, я высказал и свои скромные соображения. Дескать, приведенное решение - это не бог весть что, но чуток поправить и будет работать... И сразу получил суровую отповедь.

    Каюсь, не удержался ответа:

    Скриншот в полном виде:

    Поскольку орфотаблица составлялась без учета имен собственных и географических названий, то при проверке орфографии все такие имена и названия подсветились красным. Розовым подсвечены слова, имеющие различное ударение в зависимости от контекста - т.н. омографы.

    В программе используются словари омографов *.hmg - для различных голосовых движков. Они размещаются в подкаталоге dic рабочего каталога программы и видны в общем списке словарей. Их формат аналогичен принятому в программе "Балаболка". Рекомендуется давать словарям омографов имена, начинающиеся с символа !, тогда все они будут располагаться в начале списка словарей.

    При подключенном словаре омографов в меню "Правка - Изменить выделенное" пользователю предлагаются для выделенного омографа варианты замен с различными ударениями. Например, при подключенном "!Ru Nicolai.hmg" двойной клик по слову "глаза" выделяет его, а нажатие правой клавиши мыши выдает меню с вариантами замен.

    Файлы орфотаблицы помещаются в подкаталоге dic рабочего каталога программы и имеют расширение .orfo. Орфотаблиц может быть несколько, они видны в общем списке словарей. Может быть одновременно подключено несколько орфотаблиц, например одна для английского, другая для русского языка. Тем самым обеспечивается проверка орфографии в смешанном русско-английском тексте.

    Учтите, что опции редактирования орфотаблицы доступны лишь тогда, когда подключена (отмечена галочкой) только одна орфотаблица!

    Даже подсветка всего сразу: орфографии, омографов и похожих слов нисколько не тормозит навигацию по тексту. Тем самым проблема быстрого поиска ошибок и несуразностей в тексте практически решена.

    Кстати, тот критик с форума сразу заткнулся и больше не возникал

   P.S. А настоящее слабое место алгоритма, опубликованного в DRKB - совсем в другом! Он молчаливо предполагает, что всё, что вы видите в окне RichEdit - это некая строка текста S := RichEdit.Text. СтОит ее должным образом пропарсить, как мы получим набор позиций начала раскраски и длин окрашиваемых фрагментов, кои будем присваивать свойствам RichEdit.SelStart и RichEdit.SelLen. После чего изменим цвет очередного, выделенного таким образом фрагмента.

  Так вот, всё это верно лишь для компонента RichEdit 1.0. В более старших версиях значение свойства RichEdit.Text не совпадает с текстом, хранимым в памяти. Удалены служебные символы разметки таблиц и списков, одинарные #13 заменены на #13#10 и т.д. и т.п. Замечание: в юникодных версиях Delphi используется RichEdit 2.0.

   Поэтому, чтобы извлечь из RichEdit аутентичный текст для парсинга, необходимо использовать сообщение EM_GETTEXTEX с параметром flags := GT_RAWTEXT.

<<

13. Как добавить в программу новый язык интерфейса?

    Выбем любой из имещихся файлов языковых ресурсов в каталоге ..\languages, например, Russian.ln. Если вы не владеете русским, то возьмите English.ln. Английский в наше время знают все.

    Скопируем выбранный языковый файл, дав ему английское название испанского языка: Spanish.ln. И откроем новый файл любым текстовым редактором. Да  хоть самим Demagog'ом.

    Увидим (показаны только фрагменты):

...

[ACreate]
C=Новый
H=Новый|Создать новый документ

[AOpen]
C=Открыть...
H=Открыть...|Открыть документ

...

[lbRate]
C=___Скорость__

[lbPitch]
C=___Тембр__
...

[Msg_RulesWith]
C=Список замен по "%s". Правил: %d, применены %d раз
...

    Наша задача: перевести на испанский всё, что идет после знаков = оставляя на месте знаки | и % если такие встречаются. Вместе со знаком % не трогаем латинские буквы, идущие вплотную за ним.

    Знак нижнего подчеркивания _ на самом деле означает один пробел и предназначен для выравнивания некоторых заголовков, чтобы соответствующие элементы интерфейса располагались в правильном порядке.

    Усердно потрудившись, получим что-то вроде:

...

[ACreate]
C=Nuevo
H=Nuevo|Crear un nuevo documento

[AOpen]
C=Abierto...
H=Abierto...|Abra el documento

...

[lbRate]
C=__Velocidad__

[lbPitch]
C=__Timbre__
...

[Msg_RulesWith]
C=Lista de sustitución basado "%s". Reglas: %d, aplicado %d veces
...

    Сохраним файл Spanish.ln в том же каталоге ..\ languages в кодировке Unicode.

    При новом запуске Demagog'a в меню "Сервис - Язык (Language)" появится новый язык: Spanish.

   Тут я готов улышать возмущенные возгласы: "Автор упрощает и замалчивает!!! А Help к программе как перевести?!?" Я готов дать содержательный ответ. Вот здесь лежит архив с двумя практически аутентичными текстами справки на английскои и на эсперанто. Берите и переводите на желаемый язык. Для правки файла *.htm применяйте любой удобный для вас редактор. Я лично использую Microsoft Expression Web 4, и не надо за это кидать в меня камни, все в чем-то грешны...  В том же архиве лежит маленькая утилита htm2chm для изготовления chm-файлов из веб-страниц. При изготовлении файла Справки выбирайте пункт меню "Обычный help". Имя файла справки должно быть Demagog-Langname.chm. Где Langname - это имя, выбранное вами для языкового файла *.ln

   Так, в нашем примере имя файла Справки будет Demagog-Spanish.chm.

   Если же вы будете лениться и, переведя файл языковых ресурсов, не сделаете того же для Справки, то ничего страшного, вообще говоря, не произойдет. Если для некоторого языка интерфейса отсутствует Справка, то Demagog в таком случае покажет Справку на английском языке. И нечего возмущаться, сами виноваты. Так что, засучив рукава, принимайтесь за работу. Да, кстати. Не забудьте в переведенной вами Справке указать свое имя, дабы заслуженно прославить его

<<

14. Путь самурая. Demagog в мире Юникода

    Не претендующий на точность исторический экскурс. Давным-давно, когда компьютеры были большими мудрые люди придумали изображать каждую букву одним байтом. Байт - это 8 двоичных разрядов: 00000000 - пустой символ #0 ... 11111111 - символ #255 - буква "я" в русской кодовой таблице ANSI. Всего возможных комбинаций из 0 и 1 по восемь штук в ряду - 256. Вот и весь алфавит ANSI. От 0 до 127 - английские буквы, цифры и спецсимволы. От 128 до 255 - символы какого-нибудь национального алфавита. В руcской ANSI есть все символы русского, украинского и белорусского алфавита. Но нет например, некоторых букв немецкого, испанского и т.д. Вот откуда термин: "кодовая страница". Для каждого языка - своя.

   Шло время. Еще более умные люди решили: а давайте обозначать каждый символ 2-мя байтвми! Это уже 16 нулей и/или единиц, всего комбинаций 2 в 16-й степени = 65536. Уже пронумерованные первые 256 символов придется обозначать тоже 2-мя байтами, хотя достаточно одного. Один байт всегда будет нулевой. КОТОРЫЙ ИЗ ДВУХ? ПЕРВЫЙ ИЛИ ВТОРОЙ? Вот так кодировка Unicode сразу разделилась на две ветви: Unicode и Unicode Big Endian.

   А время, по своей неизменной привычке, продолжало идти. Еще более гениальные люди предложили: а давайте первые 256 символов обозначать, как они уже обозначены: ОДНИМ байтом! А уже дальше - ДВУМЯ. Когда исчерпаются все 65536 2-байтовых комбинаций, то новые символы обозначать уже ТРЕМЯ байтами. 2 в 24-й степени комбинаций = 16777216. Если не хватит и этого, то для новых символов возьмем уже по 4 байта... Так появилась кодировка UTF-8. Как видно из вышесказанного: для английского языка она полностью совпадает с кодировкой ANSI.

   В общем, стандарт Юникода получился достатоточно сложным. И это я еще не всё рассказал... Тем не менее, такое направление оказалось наиболее жизнеспособным. Юникод был воспринят как стандартное средство передачи текста и данных. Им поддерживается фактически любая система письма в мире, поэтому Юникод является нормой в глобальном научно-техническом сообществе.

    На сегодня Юникодом закодировано больше миллиона разных символов, охватывающих все языки мира.  Самым важным преимуществом Юникода является то, что он позволяет представлять данные в текстовом формате без установки соответствия текстовых строк и информации о кодовой странице. Например: хранение и поиск текстов на русском, иврите, французком, испанском, немецком и английском языках. С Юникодом это сделать просто - кодировка одна на всех. Потребуется добавить казахский или японский - без проблем!

    Таковы мирового масштаба причины, побудившие меня создать новую версию  Demagog'a, полностью поддерживающую Юникод  

    Путь самурая. Если кому-то покажется, что это было совсем просто, то он немножко ошибается. Здесь я раскажу об этой увлекательной эпопее.

    Не буду останавливаться на разных мелочах, которые в юникодной Delphi работают совсем не так, как ты привык. Сломался главный инстинкт программиста: один символ - это ровно один байт. Если в вашей программе есть модули, которые используют этот, переставший быть истинным факт - будьте любезны переделать. Сломался другой мощный инстикт: конец строки в тексте обозначается парой сиволов #13#10 - возврат каретки + перевод строки. В Юникоде, кроме этой неразлучной пары есть и еще комбинации. В т.ч. и одиночный #13. Когда текст загружается в компонент RichEdit, то вместо каждой сладкой парочки остается один одинешенек вышеупомянутый. Учтите это.

    И, главное. Если что-то шустро работало на ANSI-алфавите в 256 символов, то где гарантия, что на необорзи... необозримом юникодном алфавитище это будет также. Года три тому назад некоторые умники предсказывали мне, что мой любимый хеш-алгоритм перестанет работать в Юникоде. То что летало - станет ползать. Я в это не верил, но некий внутренний трепет все же испытывал, признаюсь. Тотальное тестирование показало: если принять скорость хеш-алгоритма для кодировки ANSI за 1, то в Юникоде это время колеблется в пределах 1.105 .. 1.164. Нормальным языком: если и замедлилось, то не более чем на 17%. Ура, однако. А впрочем, я так и знал.

    Если быстрый хеш-алгоритм не летал, а ползал в юникодной "Балаболке" (автору которой я разрешил одно время использовать его, наравне с методом прямого перебора), то теперь совесть моя спокойна.

    И вот, преисполненный самых радужных надежд, окрыленный внезапным быстрым развитием блицкрига... э-э, миграции проекта Demagog на юникодную Delphi, я приступил к тестированию работы словарей  формата REX, основанных на т.н. регулярных выражениях (РВ). Мощнейшее средство для корректировки текстов, которое на заре создания проекта в 2007 году в Demagog'e напрочь отсутствовало.  А в "Балаболке" было! Правда, с одной оговоркой: с русским языком РВ не работают.

    Помню этот день, 1 сентября 2010. Скачиваю в Инете знаменитый бесплатный модуль RegExpr.pas - давнее творение Андрея Сорокина, добавляю в нем к перечню буквенно-цифровых символов буквы русского языка, компилирую проект - вуа-ля, всё работает! Выкладываю версию, пишу на Форум, где разработчики TTS-софта и его пользователи вместе пасутся. Заодно предлагаю словарям регулярных выражений, вместо банального INI, дать расширение REX. От Regular EXpressions.

    Давний участник Форума - автор "Балаболки" Илья Морозов сразу подает голос: "Взяли компонент Андрея Сорокина TRegExpr и дописали русские буквы в константу RegExprWordChars?" "Точно так", - отвечаю. "...Тоже думал над этим, но к окончательному выводу так и не пришел... Я готов перейти на использование TRegExpr - чтобы обеспечить единый способ обработки правил". Переименовать ini в rex он также согласился, чтобы в обеих программах было единообразие форматов словарей.

    И вот, возвращаюсь в своем рассказе в наши дни, к самому драматическому моменту. Преисполненный радужных и так далее надежд... запускаю тест словаря типа rex. Как-то он поведет себя в Юникоде? А поведение, мягко говоря, странное... "Фирменная" демагоговская зеленая полоска даже не ползет... а имитирует вековой рост сталактитов в пещерах. На глаз движение малозаметно. Короче: в Юникоде работа rex-словарей замедлилась в 10 .. 20 раз! Твою ж мать...

    И винить некого. Сорокин в документации к RegExpr честно предупреждал, что для Юникода модуль не оптимизирован и работает крайне медленно. Кто хочет и может - усовершенствуйте. Все правильно - халявному коню в зубы не смотрят. Годы прошли, коня починить никто не захотел или не смог...

    Тут меня осенило. В Delphi, начиная с версии XE есть свой собственный, "родной" модуль работы с РВ. Читаю мануал, мне всё нравится, понятнее и проще, чем в модуле Сорокина. Uses RegularExpresions и... поехали! Что там, поехали... Понеслась птица-тройка! Потирая руки от радости, я наблюдал, как меньше чем за минуту был обработан текст в 2.8 Мб. Лишь один маленький нюанс, маленькая бочка дегтя в ложке меда отравила мое ликование. Результат оказался неверным! Потому что метасимволы \w \W \b \B - не реагировали на русские буквы! Старинная традиция в системах обработки РВ: "буквами" считаются только буквы латинского алфавита и цифры. Англосаксы изобрели теорию регулярных выражений, они же и установили правила. Остальные аборигены земного шара нервно курят в сторонке.

    Поиск решения проблемы в Инете выдал только скулеж и плач на разных форумах: как быть и что делать с кириллицей в регулярных выражениях?! Ахи да охи на разных языках... Сопли и слезы в три ручья. Твою ж мать...

    Странствия в Инет-пространстве длились уже третий день. Тотальный обыск земного шара вразумительных результатов не давал. Поздно вечером, возлежа, подобно турецкому паше, на диване, я уныло глядел в экран планшета. Может, ну его, лучше фильм посмотреть? Если бы мой верный планшет не спросил: "Язык сайта японский, превести на русский?" и если бы я не ответил: "Да", то я бы не понял, что нашел. 

    Библиотека поддержки РВ для Delphi 2005 и выше: SkRegExp. Автор: Shuichi Komiya. Поддержка Юникода. Совместимость со стандартом PCRE 5.14. Совместимость с "родным" модулем поддержки РВ в Delphi XE. Совместимость на уровне функций и методов с модулем RegExpr Андрея Сорокина. Но это - самостоятельная разработка, а не продолжение сорокинской, оговаривался Shuichi Komiya. И рекомендовал всем, кто хочет идти по его стопам, книгу Yoshiyuki Kondo "Algorithms and Data Structures for C Programmers". Из которой он заимствовал алгоритм построения недетерминированного конечного автомата для регулярных выражений. (Не пугайтесь, это всего лишь математика). Недостаток: документация только на японском. Не беда. Гуглопереводчик нам в помощь.

    Распространение: бесплатно. Программный продукт защищен лицензией MPL (Mozilla Pablic License). Это означает: исходный код, скопированный или измененный под лицензией MPL, должен лицензироваться по правилам MPL. Бери, пользуйся, переделывай, если надо, включай в любой свой проект, хоть коммерческий, хоть нет. При условии, что объявишь в своем проекте факт использования MPL-защищенного программного обеспечения и выложишь в открытый доступ его исходные коды под той же лицензией. Как говорится: попользовался сам, передай другим. На своем сайте Shuichi Komiya пишет, что заинтересован в широком распространении SkRegExp.

    "Ура, наверное..." - подумал я, написал Uses SkRegularExpressions..., проверил на маленьком примере - с русским языком всё работает нормально, а как, например с эсперанто?! Тоже алфавитно-цифровые символы и границы слов отлавливаются нормально, аборигены земного шара аплодируют стоя. "В самом деле, ура!" - решил я и запустил сакраментальный тест - 2.8 Мб. Успел заметить, что скорость практически такая же, как в "родном" дельфийском модуле РВ. А потом, примерно на 40% готовности, чудесный "самурайский модуль" завис намертво. Твою ж мать...

    Место, где происходит катастрофа я нашел быстро, и выявил своеобразный класс регулярных выражений, убивающих творение Shuichi Komiya наповал. Написал короткое консольное приложение, демонстрирующее правильный ответ для "родного" модуля РВ и бесконечный цикл для библиотеки SkRegExp. И отправил на сайт разработчика в раздел "Извещения об ошибках".

    Новую, исправленную версию библиотеки SkRegExp, и объяснение, в чем состояла ошибка, Shuichi Komiya выложил через 2 часа 23 минуты, продемонстрировав оперативность и высокий профессионализм. Остальные проверки на текстах большого объема выполнил Евгений Мирошниченко, всё отработало нормально и с высокой скоростью.

    Исходные коды SkRegExp, слегка измененные мною (чтобы стандартные сообщения выдавались не на японском, а на английском языке) содержатся в дистрибутиве Demagog'a. Они защищены лицензией MPL 2.0, см. выше. Кому надо, пользуйтесь, с соблюдением требований лицензии.

    P.S. Вообще-то, один нарушитель лицензии уже есть. В извещении о выходе "Балаболки" 2.11.0.581, последовавшем сразу за выходом Demagog 7.28.295 beta, использующего библиотеку SkRegExp под лицензией MPL, Илья Морозов сообщил: "Обновлено применение правил из словарей формата REX (спасибо Венедикту Ли)", а в русском варианте Справки к программе (и только в нем!) сухо упомянул: "Балаболка" использует библиотеку, реализующую работу регулярных выражений в стиле Perl". Вот так. Можно порадоваться, что теперь "Балаболка" тоже быстро обрабатывает РВ, но...  На мое напоминание о недопустимости сокрытия факта использования MPL-защишенного ПО и его исходных текстов, И.Морозов хранит молчание.

    Пользователи "Балаболки" должны иметь ввиду, что этот программный продукт в настоящее время не является юридически чистым с точки зрения международного права; и взять на себя ответственность за возможные правовые риски.

    Там чудеса, там леший бродит... или ловушка #128. Как я уже говорил, Delphi-программиста, работющего с юникодной версией Delphi, могут подстерегать неожиданные засады. Здесь я расскажу еще об одной.

   Недавно Шуичи Комия написал в своем блоге следующее.

    "Я думал, что #$0080 и #128 - это одно и тот же. Но столкнулся с ситувцией, когда это, кажется, не так. Результат сравнения в SkRegExp отличался у зарубежного пользователя. Регулярное выражение: \b[Ĉ]([^Ĉ\d]+) , строка для поиска: Ĉ Ĉĉĉ .  Правильный ответ: соответствие двух первых символов. Это очевидно и так и получается в моем тесте. Но в тесте пользователя соответствие не было найдено. Хуже всего было то, что ошибка не воспроизводилась и это серьезно беспокоило меня. К счастью, Пользователь-сан согласился сотрудничать, чтобы решить проблему. Много раз, чтобы определить проблемные участки кода, прходилось отправлять тестовую программу и получать результат от пользователя. Код, вызвавший ошибку, оказался таким:

    if AStr^ < #128 then

    Для Ĉ с кодом U+0108H это должно быть False. Тем не менее, результатом тестового кода стало True. Проблема была решена изменением кода на

    if AStr^ < #$0080 then

    Но, в чем же было дело?"

   Вот такой резонный вопрос задавал Шуичи Комия. А собака, как выяснилось,  была зарыта вот где. По крайней мере в Delphi XE8 десятичная и 16-ричная запись кода символа могут означать разные символы! Разяснение от разработчиков Delphi Круто, да? Десятичная запись #xxx - это символ ANSI. 16-ричная запись из двух цифр #$xx - это символ ANSI. 16-ричная запись из четырех цифр #$xxxx - это WideChar. В результате, запись #128 дает разные символы в японской и русской кодовых страницах ANSI. Что и было обнаружено при тестировании новой версии SkRegExp.

   Как вы, наверно, догадались, "Пользователь-сан", составивший контрольный пример - это был я

<<

15. "Брюки превращаются..." или что такое "фонетический алфавит"?

    В 1886 г. группа британских и французских преподавателей задалась целью разработать алфавит для передачи устной речи на любом языке. Их труд увенчался успехом, а рабочая группа превратилась со временем в Международную фонетическую ассоциацию. Более ста лет она занимается подержкой и развитием Международного фонетического алфавита. Сокращенно - МФА или, в английском написании - IPA. От International Phonetic Alphabet. Кто изучал английский язык, наверняка помнит замысловатые "знаки транскрипции". Это МФА и есть.

    На основе МФА созданы алфавиты для некоторых, ранее бесписменных языков. Профессиональные оперные певцы, исполняющие арии на многих языках, широко пользуются МФА. Естественно, что МФА полезен при синтезе речи, когда требуется исправить произношение того или иного слова, сообщив голосовому движку его правильное произношение. Но как это сделать? Как составить правило корректировки произношения с помощью МФА, большинство знаков которого отсутствует на клавиатуре! Будьте любезны, убедитесь воочию.

    Родство с латиницей явно прослеживается. Но, чтобы передать особенности произношения любого из языков мира, пришлось к 26 буквам добавить еще в три раза больше. Каждый новый символ всё менее и менее походил на прежние. В ход также пошли надстрочные и подстрочные значки, т.н. диакритики. Сложное дело - всемирная азбука! Приглядитесь: в ней даже "двоеточие" и "апостроф" совсем не такие, как на клавиатуре.  Но задачу: научить компьютер понимать фонетическую запись - никто не отменял.

    Решение оказалось банальным. Если использовать латинские буквы, цифры и прочие специальные клавиатурные символы не только по одному, а в и комбинациях по два, то вот вам, пожалуйста. Каждому символу МФА найдется соответствие. На глаз запись выглядит тоже непрезентабельно, ну, да компьютеру всё равно. Так появился машиночитаемый фонетический алфавит Speech Assessment Methods Phonetic Alphabet (SAMPA) и его расширение X-SAMPA. Некоторые голосовые движки, имеющие собственную систему корректировки произношения, как раз используют SAMPA для этой цели. К ним, например, относятся русскоязычные голоса: Acapela Alyona, IVONA Tatyana, IVONA Maxim.

    Вот и всё про SAMPA, потому что тег SAPI5 <PRON SYM="..."/>, предназначенный как раз для чтения фонетической записи, этого алфавита не разумеет. Так какого рожна ему надо?! Тут-то и начинается самое интересное. Тег <PRON> понимает лишь то, что для него придумали затейники из Майкрософт. А придумали они по-первоначалу SAPI Phone Set - набор фонетических алфавитов для нескольких, самых распространенных языков. Английский, китайский, японский... полный список (он невелик) вы найдете на сайте Майкрософт. Каждая фонема того или иного языка изображается некоторой комбинацией маленьких латинских букв.

    Долго ли, коротко ли, но этим дело не ограничилось. Последовала новая разработка: Microsoft Universal Phone Set (UPS), полностью основанная на МФА. Фонемы изображаются большими латинскими буквами или их комбинациями по две и по три. Диакритики выглядят как комбинации из трех маленьких латинских букв. Использутся также цифры 1, 2; знак подчеркивания _; вертикальная черта |; и знак +. UPS применимо для всех голосов, кроме тех, которые заточены под SAPI Phone Set, см. выше. Фонемы на письме разделяются пробелом.

    На первый взгляд UPS-транскрипция вызывает оторопь. Да, согласен: и на второй тоже. Но, опять же, компьютеру всё равно!

    Входящие в состав Windows 10 искусственные голоса: MS Irina Desltop - Russian и MS Pavel Mobile - Russian - поддерживают тег <PRON> с фонетикой UPS. Больше того, это верно и для упомянутых выше IVONA Tatyana, IVONA Maxim!

    Что открывает возможность управлять их произношением исключительно средствами SAPI5, вставляя в читаемый текст тег <PRON>. Для этой цели в Demagog'e есть опция "Правка - Фонетическая транскрипция (Shift+F1)". Фонетичская таблица-подсказка поможет составить фонетическую запись того или иного слова или даже целой фразы. Можно просто вставлять из буфера обмена транскрипцию слов в МФА (получив ее, например, здесь) и легким движением руки перевести в UPS...

    А кнопочка внизу слева запускает проверку: читается ли фонетическая запись так, как мы хотим?

    Если да, то жмем кнопку с галочкой и в текст с позиции курсора вставляется <PRON SYM="B RR pal S1 YX K pal IH P RR pal IH V RR AEX SC lng S1 AE J YX TS AX V + IX low L pal IH G S1 A N T N IX low J AX SR S1 O RR T IX low"/>

    Вот как это звучит

<<

16. Формат DXT - "документ Demagog"

    Изначально Demagog работал только с т.н. "плоскими" текстами. Как Блокнот Windows, проще говоря. А прочие поддерживаемые форматы на лету преобразовывал в этот самый плоский до банальности текст. Ни тебе курсива, ни жирного шрифта. Выделить что-то подчеркиванием... тоже низзя! аяяй!

    Созданный пользователем перечень закладок хранился в файле настроек Demagog'a - $.cfg. При его порче или случайном удалении пропадали результаты долгого, кропотливого труда по разметке текста закладками. А картинки, импортированные из документов MS Word или электронных книг, хранились в автоматически создаваемых папках-галереях. Которые Demagog, как корова лепешки, оставлял везде, где пасся... то бишь, где открывал какие-либо файлы.

    "Работа проделана большая, но дальше так дело не пойдет", - подумал я и задействовал поддержку программой собственного текстового формата. Demagog teXT - DXT. (Название и сама идея добавления этого формата в программу были ранее предложены Евгением Мирошниченко). Плоский текст по-прежнему поддерживается, но картинок за собой в котомке больше не носит. Закладки, как и раньше, хранятся в настойках Demagog'a, но...

    Файл формата DXT хранит в себе, помимо текста: упомянутый список закладок; а также импортированные картинки. При редактировании текста поддерживаются общепринятые стили: выравнивание влево, вправо, по центру. Шрифт: обычный, жирный, курсив, подчеркнутый, зачеркнутый. Допускается совмещение в одном тексте фрагментов, написанных разными шрифтами.

    Любая часть текста может быть оформлена в виде т.н. "маркированного списка". Доступно создание простых таблиц, типа "шахматки".

    По предложению Евгения Мирошниченко (подготовившего также соответствующие контрольные тесты) реализовано автоматическое распознавание "внедренного оглавления" в документах MS Word - .docx. Если такое оглавление присутствует в docx-файле, то оно будет преобразовано в список закладок Demagog'a.

    Если текст имеет закладки и/или импортированные картинки, то при его сохранении в Demagog'e, по умолчанию предлагается формат DXT.

    DXT, в основном, соответствует спецификации RichEdit 4.1 - подмножеству известного межплатформенного формата RTF. Demagog дает возможность сохранять DXT -> RTF. За исключением Галереи импортированных картинок и списка закладок Demagog'a - эти данные игнорируются. В этой части форматы DXT и RTF несовместимы.

    Под Windows 10 для формата DXT дополнительно доступны: выравнивание текста по ширине;  вставка картинок прямо в текст перетаскиванием или из буфера обмена; изменение ширины столбцов таблицы перетаскиванием их границ мышью.

    Документы MS Word, перенесенные из буфера обмена (например, в контекстном меню "Вставить, как новый документ", имеют вполне приемлемый вид.

    Как видим, основные элементы форматирования совпадают. Такой dxt-файл сохраняется в rtf вместе с имеющимися в нем картинками.

<<

17. Извлечь шляпу из кролика... или текст любой ценой

    Что делать, если надо прочесть текст, формат которого непонятен Demagog'y?

    Вариант 1. Написать гневное письмо автору, мол немедля включите в свою программу поддержку файлов формата ".hz", ".bla", ".hren" и т.д. На что автор ответит, что это противоречит принципу минимализма, и, вообще, он - не раб на галерах.

    Вариант 2. Найти в Инете среди великого множества свободно-распространяемого ПО консольный конвертер, который принимает на входе ваш файл, и создает новый файл, содержащий только текст. Что-то вроде: AnyConverter.exe "Важный документ.hren" "Важный документ.txt".

   Что? Не нашли ничего подобного? А значит, этот формат никому не известен и никому не нужен. А вот погуглите "pdf to txt" и сразу поймете всю важность проблемы с форматом PDF. Его даже MS Word не откроет, нужно инсталировать Adobe Acrobat - такого же монстроподобного зверя. Цирк, да и только. Так чего же вы хотите от Demagog'a? Аа-а... текст любой ценой! Вынь, да положь.

   Начиная с версии 7.28.320 Demagog поддерживает подключение внешних консольных текстовых конвертеров. Например, для получения текста из pdf-документа, можно воспользоваться свободно-распространяемым конвертером xdoc2txt. Скачать его можно на сайте разработчика или здесь.

   Вторая ссылка содержит также документацию на русском языке. Становится понятно, что сей конвертер - довольно универсален и позволяет вытаскивать текст из документов разных других форматов. Если xdoc2txt.exe поместить в рабочую папку Demagog'a и перезапустить программу, то увидим, что в диалоге открытия файлов появились дополнительно: Adobe PDF, MS Excel, OpenDocument, MS PowerPoint. Именно так я прописал настройки в ..\profiles\aliens.lst.

   При записи настроек в aliens.lst применяются следующие обозначения:

%1 - полное имя исходного файла

%2 - полное имя выходного текстового файла, такое же, как %1, но с расширением .txt

%~p1 - путь к файлу из %1

%~n1 - короткое имя файла из %1 (т.е. без пути и без расширения)

   Упомянутый в начале "условный конвертер" выглядел бы в настройках так:

   Хреновые файлы (.hren ...)|.hren|.hre|.hru=AnyConverter.exe %1 %2

   Сперва идет поясняющий текст - та строчка, которая будет показана в диалоге открытия файлов. После вертикальной черты - перечень расширений, которые относятся к указанному типу файлов. Разделитель - опять же вертикальная черта. И, в завершение, после знака равенства - собственно командная строка для конвертера. Указание ему, что надо делать, чтобы создать временный текстовый файл в кодировке utf-8, с тем же именем и в том же месте, где исходный документ.

   Конвертация документа в плоский текст происходит незаметно для пользователя, и текст в окне Demagog'a появляется так же быстро и непринужденно, как если бы его извлек из документа сам Demagog. 

   В зависимости от конвертера, запись командной строки может выглядеть изящно и коротко, или быть более громозкой. К примеру, для xdoc2txt, который автоматически создает текстовый файл с тем же именем, это довольно просто:

    Adobe PDF|.pdf=xdox2txt.exe -f -8 %1

    Кстати, конвертер совсем не обязательно помещать в рабочую папку Demagog'a! Можно просто указать в настройках полный путь к его исполняемому файлу. Вот пример использования portable-программы Text Mining Tool, в состав которой входит консольная утилита преобразования файлов .pdf, .doc, .rtf в плоский текст:

    Adobe PDF|.pdf=d:\2 - Install\Misc programs\Text Mining Tool 1.1.42\minetext.exe %1 %2

   Серым цветом показан путь к консольной утилите, как он выглядит на моем компьютере. Аналогичный пример для утилиты blb2txt:

    Adobe PDF|.pdf=d:\000\blb2txt.exe -f %1 -v %~p1 -p %~n1 -e "utf8"

   И т.д. и т.п. Принцип, полагаю, ясен.

    В настройках можно прописать любое количество конвертеров, каждый из которых будет обрабатывать определенные типы файлов. Если конвертер не найден, то соответствующие ему строки в aliens.lst - игнорируются. Если нет ни одного конвертера из перечисленных в настройках, то aliens.lst игнорируется целиком.

<<

Заключение

   На Demagog'a в Инете уже достаточно ссылок, в основном они ведут ко мне на страницу. Но есть и отдельно размещенные копии. Братья и сёстры во Инете! Актуальный экземпляр Demagog'a со всеми причиндалами вроде аудио-кодеков, файлов справок и русской и английской орфотаблиц - скачивать нужно только с моей страницы: http://aloys.narod.ru/Demagog.zip

Что говорят

История версий

<<<