Это — продолжение, вернее ответ на задачу из статьи "Лингвистическая загадка. Переводим с мертвого языка".
Времени нет катастрофически, но как известно его никогда не бывает, а раз уж обещал, статью приходится писать. Засим еще раз извиняюсь за опоздание.
Ответ
Для нетерпеливых сразу ответ, который кстати на момент написания статьи, кроме единственного человека (не с хабра), полностью не разгадал никто. Но об этом ниже…
Упомянутая известная фраза про «Глокую куздру» (привет AndreyDmitriev), что есть цитата из книги Успенского «Слово о словах», была коварно помещена мной в середину текста. Остальное, как уже говорилось, добил другими из той же темы, причем немного даже в «старорусской» манере...
не произноси будлания глокого на куздрение бокра своего, ибо вострепещут будлающие, да воссияют будлаемые. глокая куздра штеко будланула бокра и курдячит бокрёнка. да не будет у бокра куздры, а у куздры бокра перед лицем моим, ибо я страшно будланул, и мною так будлануто.
Было множество попыток от разных людей и в верном направлении и не очень. Вашему покорному слуге было очень интересно следить за самим процессом «разгадывания». На этом, всем участникам огромнейшее спасибо.
Несколько человек, после моих примеров, открыли для себя тикль или решили выучить его серьезнее («новобранцам» особый привет), что меня как его разработчика тоже не может не радовать!
В общем с моей стороны сплошной позитив…
Думается, предложи я работу отличившимся, интерес к задаче был бы много выше, но к сожалению вакансий на тот момент у нас не было, поэтому что есть — то есть.
Простой пример машинного перевода (TCL в три строчки)
Здесь совсем уж простенькие исходники на TCL со словарями для преобразования туда-сюда. Они только чтобы показать работоспособность «машинного» перевода (в три строчки), но как примеры не совсем дееспособны. Здесь, чтобы применить слоговую и символьную замены, различающие приставки и суффиксы, в словарях использовались пробелы, точки и запятые. Такой словарь довольно громоздкий и не удобен для разбора, поэтому ниже приведу алгоритмы посложнее, но более легким в понимании словарем.
Тикль есть под linux как правило уже из коробки (tclsh), под windows (после установки tcl) вместо tclsh лучше использовать wish из-за множественных кодировок). Если будут желающие примеры на python, перепишу под него и выложу в пост.
- Туда:
С русского на «мертвый»
# словарь туда set map1 {шт სტ стр სცლგ ст სცტ сс შც гл გილრ во ფაგ ла რეოლ буд პაგდლ бу პეულ бо პეალ зд ზდ прои პგლოე зно ზგა окая აგელეო кая კელეო кра კგლეგ ка კეოლეგ ку კეუგლ ко კეალ то გტაგ ок აგლ ну მეუგლ ит ედგეგ ат ოდგ ут ულდგ пер ბლგ ая ოლეოგ ия ელეოგ ю ეუგლ {и } {ელ } и, ელ, и. ელ. {я } {ეოგლ } я, ეოგლ, я. ეოგლ. {а } {ოლ } а, ოლ, а. ოლ. {е } {ილ } е, ილ, е. ილ. {о } {აგ } о, აგ, о. აგ. {у } {უგ } у, უგ, у. უგ. {м } {ნოგ } м, ნოგ, м. ნოგ. {к } {ხგ } к, ხგ, к. ხგ. {не } {მეაგ } не, მეაგ, не. მეაგ. ё ეა щ შჩ ы ეგ ю ეუ я ეო а ო б პ в ვ г ხ д დ е ი ж ზ з ჟ и ე й ე к კ л რ м ნ н მ о ა п ბ р ლ с ს т ტ у უ ф ფ х გ ц ც ч ჩ ш შ ъ _ ь ე э ი} # оригинальный текст set decStr "Не произноси будлания глокого на куздрение бокра своего, ибо вострепещут будлающие, да воссияют будлаемые. Глокая куздра штеко будланула бокра и курдячит бокрёнка. Да не будет у бокра куздры, а у куздры бокра перед лицем Моим, ибо Я страшно будланул, и Мною так будлануто." # преобразуем по словарю (но сначала lower case) set encStr [string map $map1 [string tolower $decStr]] # stdout puts $encStr
- Обратно:
С «мертвого» на русский
# словарь обратно set map2 {სტ шт სცლგ стр სცტ ст შც сс გილრ гл ფაგ во რეოლ ла პაგდლ буд პეულ бу პეალ бо ზდ зд პგლოე прои ზგა зно აგელეო окая კელეო кая კგლეგ кра კეოლეგ ка კეუგლ ку კეალ ко გტაგ то აგლ ок მეუგლ ну ედგეგ ит ოდგ ат ულდგ ут ბლგ пер ოლეოგ ая ელეოგ ия ეუგლ ю {ელ } {и } ელ, и, ელ. и. {ეოგლ } {я } ეოგლ, я, ეოგლ. я. {ოლ } {а } ოლ, а, ოლ. а. {ილ } {е } ილ, е, ილ. е. {აგ } {о } აგ, о, აგ. о. {უგ } {у } უგ, у, უგ. у. {ნოგ } {м } ნოგ, м, ნოგ. м. {ხგ } {к } ხგ, к, ხგ. к. {მეაგ } {не } მეაგ, не, მეაგ. не. ეა ё შჩ щ ეგ ы ეუ ю ეო я ო а პ б ვ в ხ г დ д ი е ზ ж ჟ з ე и ე й კ к რ л ნ м მ н ა о ბ п ლ р ს с ტ т უ у ფ ф გ х ც ц ჩ ч შ ш _ ъ ე ь ი э} # мертвый текст set encStr "მეაგ პგლოეზგასელ პაგდლრეოლმელეოგ გილრაგლახაგ მოლ კეუგლზდლიმეილ პეალკგლეგ სფაგიხაგ, ეპეალ ფაგსცლგიბიშჩულდგ პაგდლრეოლეუგლშჩეილ, დოლ ფაგშცელეოგეუგლტ პაგდლრეოლინეგილ. გილრაგელეო კეუგლზდლოლ სტიკეალ პაგდლრეოლმეუგლრეოლ პეალკგლეგ ელ კეუგლლდეოჩედგეგ პეალკლეამკეოლეგ. დოლ მეაგ პაგდლიტ უგ პეალკგლეგ კეუგლზდლეგ, ოლ უგ კეუგლზდლეგ პეალკგლეგ ბლგიდ რეცინოგ ნაენოგ, ეპეალ ეოგლ სცლგოშმაგ პაგდლრეოლმეუგლრ, ელ ნმაეუგლ ტოხგ პაგდლრეოლმეუგლგტაგ." # преобразуем по словарю set decStr [string map $map2 $encStr] # stdout puts $decStr
Собственно разбор полётов
Я не лингвист в прямом смысле этого понятия, но во первых, бегло говорю и пишу на нескольких языках из разных языковых групп (причем на некоторых из них, как на родном). Во вторых, по работе связан с разбором и анализом текстов, в том числе многоязычных (поисковые системы, распознавание, индексирование и т.д. и т.п.). В третьих, опять же частично по роду деятельности, прекрасно понимаю как некоторые языки развивались и видоизменялись со временем. К тому же я программист, т.е. преобразования из одного в другое хоть «машинным» способом, хоть в голове, присущи мне в определенной степени тоже.
В качестве начального примера возьмем некоторые «преобразования», произошедшие с отдельными языками давным давно:
- kiks <-> Kekse <-> koekjes <-> cookies — датский, немецкий, голландский (нидерландский) и английский соответственно.
- ting <-> das Ding <-> het ding <-> the thing — они же;
- каждого года <-> кожнага года <-> кожного року <-> každý rok — русский, белорусский, украинский, словацкий;
Что я хотел бы здесь уточнить: я не могу сказать, в отличии возможно от лингвиста, в какой последовательности и что здесь куда видоизменялось, но чисто практическое понятие этой морфологии я имею, так сказать «математику уравнения» прекрасно себе представляю.
Грамматические видоизменения синтаксиса предложений при переводе я не рассматривал в принципе, т.е. в искомом тексте все «переводилось» дословно. Просто при полном видоизменении, например перестановке слов, шансы восстановить русский текст по такому небольшому отрывку стремились к нулю. Сравните например даже такие близкие языки, одной языковой группы, как датский и немецкий.
Дословный перевод (морфологически правильно, но синтаксически никуда не годится):
[DK] Du behøver ikke komme, hvis du har bedre ting for
[DE] Du brauchst nicht kommen, falls du hast bessere Dinge vor
Правильный перевод на немецкий:
[DK] Du behøver ikke komme, hvis du har bedre ting for
[DE] Du brauchst nicht zu kommen, falls du etwas besseres vorhast
Поэтому, еще раз повторюсь, перевод осуществляем дословно, без изменения порядка слов — т.е. остается характерный русскому языку синтаксис.
Определим наш язык как немного «рычащий» и «хыкающий» и сделаем некоторые буквы в определенных местах «плохо слышимыми» или нечитаемыми. Слегка усложним морфологию написания языка, а слова в нем сделаем чуть длиннее чем в русском. То что должно получится, должно напоминать русский с примесью с одной стороны скандинавских (и возможно других германских) языков, с другой стороны иметь что-то от языков тюркской группы.
Итак, приступим…
Переводим на «мертвый» язык
В оригинале, я переводил сразу используя символы грузинского алфавита, но люди в комментариях дали понять что «иероглиф» «иероглифу» рознь (сложны к восприятию) — поэтому перевод будем делать пока кириллицей, лишь в конце используя грузинский алфавит.
Для начала небольшая подпрограмма позволяющая простенько и со вкусом изменять слоги и буквы, при этом «различая» начало и конец слов.
# позволяет преобразовывать текст словарем и регулярками:
proc magic_text {args} {
set text [lindex $args end]
foreach {op val} [lrange $args 0 end-1] {
switch -- $op
-regexp {
foreach {re val} $val {
regsub -nocase -all $re $text $val text
}
}
-map {
set text [string map -nocase $val $text]
}
-default {
error "uknown operation '$op'"
}
}
return $text
}
# расширенная версия, где сначала помечаем слова, выделив начало и конец спецсимволами:
# ... ^слово$, ^следующее$ ... - а после преобразований удаляем эти маркеры
proc Translate {dictMap encText} {
magic_text -regexp {{(m[^s[:punct:]]+M)} {^1$}} -map $dictMap -map {^ "" $ ""} $encText
}
Проба пера — здесь используя простенький словарь, попробуем переписать фразу «мама мыла раму» во множественном числе, и вместо «рамы» будет «Рома».
# пример словаря (^ - начало слова, $ - конец):
% Translate {^ма Ма ла$ ли а$ ы у$ "" ^ра Ро} "мама мыла раму, рама пищала и стонала."
Мамы мыли Ром, Ромы пищали и стонали.
Собственно приступаем к созданию словаря для нашего «мертвого» языка.
# словарь туда
set RuXy {
шт ст стр сцрх ст сцт сс шц
гл херл во фох ла ляр
буд бохдр бу бюр бо бёр
зд жд прои бхраи зно жхо
окая охиря кая киря кра кхры ка кяры ку кюхр
ко кёр то хтох
ок охр ну нюхр
ит идхы ат адх
ут урдх пер прх
ая арях ия ирях ю юхр
и$ ир
я$ ях
а$ ар
е$ ер
о$ ох
у$ ух
м$ мах
к$ гх
не$ ниох
}
# 1 оригинальный русский
puts 1:[set ru "Не произноси будлания глокого на куздрение бокра своего, ибо вострепещут будлающие, да воссияют будлаемые. Глокая куздра штеко будланула бокра и курдячит бокрёнка. Да не будет у бокра куздры, а у куздры бокра перед лицем Моим, ибо Я страшно будланул, и Мною так будлануто."]
# 2 переводим :
puts 2:[Translate $RuXy $ru]
Результат исполнения (перевода):
1:Не произноси будлания глокого на куздрение бокра своего, ибо вострепещут будлающие, да воссияют будлаемые. Глокая куздра штеко будланула бокра и курдячит бокрёнка. Да не будет у бокра куздры, а у куздры бокра перед лицем Моим, ибо Я страшно будланул, и Мною так будлануто.
2:ниох бхраижхосир бохдрлярнирях херлохрогох нар кюхрждрениер бёркхры сфохегох, ибёр фохсцрхепещурдх бохдрлярюхрщиер, дар фохшциряхюхрт бохдрляремыер. херлохиря кюхрждрар стекёр бохдрлярнюхрляр бёркхры ир кюхррдячидхы бёркрёнкяры. Дар ниох бохдрет ух бёркхры кюхрждры, ар ух кюхрждры бёркхры прхед лицемах Моимах, ибёр ях сцрхашнох бохдрлярнюхрл, ир Мноюхр тагх бохдрлярнюхрхтох.
Кстати, если ввести некоторые конвенции при чтении (например «р» и «х» в конце почти всегда не произносятся), то можно сходу прочитать все предложение почти как на русском.
Цель достигнута, теперь просто наложим грузинский алфавит, соблюдая гласные и согласные (чтобы не совсем уж усложнять).
Ниже скрипт, использующий уже грузинский алфавит, и переводящий туда и обратно:
# словарь туда
set RuXz {шт სტ стр სცლგ ст სცტ сс შც гл გილრ во ფაგ ла რეოლ буд პაგდლ бу პეულ бо პეალ зд ზდ прои პგლოე зно ზგა окая აგელეო кая კელეო кра კგლეგ ка კეოლეგ ку კეუგლ ко კეალ то გტაგ ок აგლ ну მეუგლ ит ედგეგ ат ოდგ ут ულდგ пер ბლგ ая ოლეოგ ия ელეოგ ю ეუგლ и$ ელ я$ ეოგლ а$ ოლ е$ ილ о$ აგ у$ უგ м$ ნოგ к$ ხგ не$ მეაგ ё ეა щ შჩ ы ეგ ю ეუ я ეო а ო б პ в ვ г ხ д დ е ი ж ზ з ჟ и ე й ე к კ л რ м ნ н მ о ა п ბ р ლ с ს т ტ у უ ф ფ х გ ц ც ч ჩ ш შ ъ _ ь ე э ი}
# словарь обратно
set XzRu {სტ шт სცლგ стр სცტ ст შც сс გილრ гл ფაგ во რეოლ ла პაგდლ буд პეულ бу პეალ бо ზდ зд პგლოე прои ზგა зно აგელეო окая კელეო кая კგლეგ кра კეოლეგ ка კეუგლ ку კეალ ко გტაგ то აგლ ок მეუგლ ну ედგეგ ит ოდგ ат ულდგ ут ბლგ пер ოლეოგ ая ელეოგ ия ეუგლ ю ელ$ и ეოგლ$ я ოლ$ а ილ$ е აგ$ о უგ$ у ნოგ$ м ხგ$ к მეაგ$ не ეა ё შჩ щ ეგ ы ეუ ю ეო я ო а პ б ვ в ხ г დ д ი е ზ ж ჟ з ე и ე й კ к რ л ნ м მ н ა о ბ п ლ р ს с ტ т უ у ფ ф გ х ც ц ჩ ч შ ш _ ъ ე ь ი э}
# 1 оригинальный русский
puts 1:[set ru "Не произноси будлания глокого на куздрение бокра своего, ибо вострепещут будлающие, да воссияют будлаемые. Глокая куздра штеко будланула бокра и курдячит бокрёнка. Да не будет у бокра куздры, а у куздры бокра перед лицем Моим, ибо Я страшно будланул, и Мною так будлануто."]
# 2 перевод на мертвый используя словарь $RuXz
puts 2:[set xz [Translate $RuXz $ru]]
# 3 перевод на русский используя словарь $XzRu
puts 3:[set ru2 [Translate $XzRu $xz]]
Ну и результат исполнения (перевода):
1:Не произноси будлания глокого на куздрение бокра своего, ибо вострепещут будлающие, да воссияют будлаемые. Глокая куздра штеко будланула бокра и курдячит бокрёнка. Да не будет у бокра куздры, а у куздры бокра перед лицем Моим, ибо Я страшно будланул, и Мною так будлануто.
2:მეაგ პგლოეზგასელ პაგდლრეოლმელეოგ გილრაგლახაგ მოლ კეუგლზდლიმეილ პეალკგლეგ სფაგიხაგ, ეპეალ ფაგსცლგიბიშჩულდგ პაგდლრეოლეუგლშჩეილ, დოლ ფაგშცელეოგეუგლტ პაგდლრეოლინეგილ. გილრაგელეო კეუგლზდლოლ სტიკეალ პაგდლრეოლმეუგლრეოლ პეალკგლეგ ელ კეუგლლდეოჩედგეგ პეალკლეამკეოლეგ. დოლ მეაგ პაგდლიტ უგ პეალკგლეგ კეუგლზდლეგ, ოლ უგ კეუგლზდლეგ პეალკგლეგ ბლგიდ რეცინოგ ნაენოგ, ეპეალ ეოგლ სცლგოშმაგ პაგდლრეოლმეუგლრ, ელ ნმაეუგლ ტოხგ პაგდლრეოლმეუგლგტაგ.
3:не произноси будлания глокого на куздрение бокра своего, ибо вострепещут будлающие, да воссияют будлаемые. глокая куздра штеко будланула бокра и курдячит бокрёнка. да не будет у бокра куздры, а у куздры бокра перед лицем моим, ибо я страшно будланул, и мною так будлануто.
Перевод с «мертвого» языка
Перед публикацией статьи-задачи, я проверял на себе возможность нахождения решения. Конечно это далеко не чистый тест (ведь результат мне известен), но я подошел к разбору морфологии чисто «научно», используя некоторые инструменты и изначально переведя своим словарем совсем другой отрывок, взяв кусок текста случайной позицией, мне неизвестной, из другого произведения и работая в большенстве только с грузинским алфавитом (который мне кстати тоже чужд).
Должен заметить, что мне представлялось почти невозможным сделать перевод полностью автоматически или полностью вручную. В моем понимании, я и компьютер будем работать постоянно в сцепке.
В результате сценарий обратного перевода, как это делал я:
- Компьютерный анализ текста (использовался пропритарный VDK, самописные фильтры к нему, стемеры русского и куча скриптов, изначально пустой словарь трансляции алфавита). Результат анализа — множество вариантов неправильного текста на кирилице, в которых все в именительном падеже, с универсальной морфологией в неопределенной форме.
- Анализ этих вариантов текстов вручную (поиск чего нибудь читабельного). Цель — увеличить словарь, использующийся при компьютерном анализе. Повторить с шага 1. Если читабельность текста стала хуже, откатиться к предыдущему словарю.
Вот в принципе и все.
Человек, разгадавший эту загадку и переведший текст полностью, вплоть до совпадения хеша, прислал мне ответ по е-майлу. Позже он описал способ, которым он это сделал, который в корне отличается от того, как к разгадыванию и переводу подошел я.
К сожалению, по многим причинам (время в том числе) он пока не горит желанием присоединится к хабрасообществу (и инвайты у меня пока все вышли, прислал бы назло:). Но если вдруг получится совместно или может он разрешит опубликовать решение от его имени, я сделаю это с большим удовольствием. Его решение, вернее концепция оного, несмотря на то, что тонкости к сожалению я не понял, т.к. полностью не видел, все равно очень и очень впечатляет.
По непонятным для меня причинам, этот скромник не хотел, чтобы я упоминал его имя в статье, да и в то, кто он в действительности и откуда, я к сожалению тоже не был посвящен. Стиль общения позволяет предположить, что человек этот еще очень молод. Хотя… В общем, тут пока сплошные тайны мадридского двора. Однозначно только могу сказать, что он — «русский» (по нынешним временам правильнее — русскоговорящий:).
…
Еще раз благодарю всех участвовавших.
Автор: sebres