Люди иногда сознательно сокращают слова, набирая SMS или твиты — чтобы потратить меньше денег или укоротить сообщение.
Идея возникла, когда на одном из многочисленных «сократителей URL» я увидел надпись «Shrink text». И мне пришло в голову, что вот он возьмёт, и сократит сам текст: выдаст что-нибудь вроде «shrnk txt». Конечно, сервис всего лишь заменял в тексте URL, но я подумал, что можно было бы сокращать и сам текст.
Не знаю, как в английском, а в русском, по-моему, можно убрать довольно много гласных букв, а текст будет по-прежнему читаться. Я решил испытать идею, и написал этот сократитель.
Программа преобразует текст на русском языке, выкидывая из него некоторые буквы и символы. Прошу рассматривать это как забавную игрушку и программой не злоупотреблять.
Зависимости
Программа написана на Literate Haskell (это значит, что то, что, вы сейчас читаете, и есть программа!). Используются следующие модули:
> import System.IO.UTF8 as U
> import Data.Char (toLower)
> import Text.Regex.Posix ((=~))
> import Data.Char (isPunctuation)
TODO: Я использую старый способ работать с UTF-8 (utf8-string), надо переделать под новую библиотеку text.
Алгоритм
Данная программа «сжимает» русский текст так:
I. Из слов убираются (почти) все гласные и мягкие знаки,
> filterVowels = filter (`notElem` (aVowels ++ jVowels))
Неприкосновенны гласные, которые:
I.a. являютя частью приставки «не-»
> rmVowels = map wordFilter
> where
> wordFilter ('н':'е':cs) = "не" ++ wordFilter cs
I.b. стоят в трёх- и менее -буквенных словах
> wordFilter w = if length w <= 3
> then w
I.c. стоят в начале или конце слова
> else
> let (prefix,inner,ending) = splitWord w
> in prefix ++ (ajaFilter inner) ++ ending
> splitWord s = let p = takeWhile dontRemove s
> r = drop (length p) s
> e = reverse $ takeWhile dontRemove $ reverse r
> m = take ((length r) - (length e)) r
> dontRemove c = c `elem` vowels || isPunctuation c
> in (p,m,e)
I.d. являются комбинациями со звуком «й»: «-ою-», «-ая—» и проч.
> ajaFilter [] = []
> ajaFilter s = let (b,m,a) = s =~ diftPat :: (String,String,String)
> diftPat = "[" ++ vowels ++ "][" ++ jVowels ++ "]"
> in (sameConsFilter b) ++ m ++ (ajaFilter a)
I.e. стоят меж двух одинаковых согласных
> sameConsFilter [] = []
> sameConsFilter s =
> let (b,m,a) = s =~ sameConsPat :: (String,String,String)
> sameConsPat = "(["++consonants++"])[" ++ vowels ++ "]\\1"
> in (filterVowels b) ++ m ++ (sameConsFilter a)
Программа использует такой список гласных:
> vowels = aVowels ++ jVowels
где есть и простые гласные (к ним же причислен и мягкий знак)
> aVowels = "аиоуыэь"
и дифтонгообразующие (не знаю правильного термина — в общем, дающие звук «й»),
к ним же причислена и буква «й»:
> jVowels = "яйёюе"
Для некоторых правил требуется также список русских согласных:
> consonants = "бвгджзклмнпрстфхцчшщ"
II. из предложений убираются знаки препинания, кроме точек, вопросительных и восклицательных знаков
> rmSomePunctuation = filter (not . null) . map rmTrailing
> where rmTrailing = reverse . rmHead . reverse
> rmHead [] = []
> rmHead s@(c:cs) = case c `elem` rmlist of
> True -> rmHead cs
> False -> s
Список подлежащих удалению знаков препинания:
> rmlist = ",;-—:–"
III. из текста удаляются некоторые предлоги (в телеграфном стиле)
> rmPrepositions = filter (`notElem` preps) . words
> where preps = [ "в", "во", "на", "над", "к", "от", "из"
> , "по", "под", "через" ]
IV. для пущей стилизации текст пишется в нижнем регистре
> tolower = map toLower
Использование программы
Программу можно использовать как простой unix-фильтр: он читает текст из потока stdin и печает «сжатый» текст в стандартный вывод (stdout).
> main = U.interact $ (++ "\n") . twtrize
> twtrize = unwords . filter ( not . null ) .
> rmVowels . rmSomePunctuation . rmPrepositions . tolower
Пример:
$ printf "Гласные, а также некоторые предлоги — как, например, «на», — из \
текста удаляются, но какие-то остаются.\n" | runhaskell twtrize.lhs
глсные а ткже нектрые прдлги как нпрмр «на» ткста удляются но какие-то
остаются.
Последняя версия: исходник здесь. Лицензия: BSD-3.



Вот это да! я по такому алгоритму лекции в институте сокращал )) даже достал тетрадку 7 летней давности, ой помню ругались люди тогда ...
ОтветитьУдалитьВандализм это, согласен :)
ОтветитьУдалитьБыло бы занятно к этому скрипту веб-интерфейс прикрутить или в какой-нибудь твиттер-клиент его встроить.
ОтветитьУдалитьа в немецком это почти официальный способ сокращения слов - выкидывание гласных.
ОтветитьУдалитьСерёжа, срочно патентуй :-) Потом ваяешь вебморду и раскручиваешь как средство отправки SMS-ок. Предвижу грандиозный успех предприятия :-)
ОтветитьУдалитьСам в своё время сокращал лекции с помощью смеси математических и алгоритмических символов, такой специальный машинописный язык. Народ, бравший у меня лекции, сильно ругался, что ничерта понять нельзя.
А программа хороша.
Вот очень люблю я тебя за такие посты.
ОтветитьУдалитьВот бы обратное действие этот алгоритм мог делать =)
ОтветитьУдалитьВы филологией занимались? Или каким-другим образом придумали такой оригинальный способ?
ОтветитьУдалить2 axet:
ОтветитьУдалитьДа нет, филологического образования у меня нет, я математик (прикладной). Просто по опыту знаю, что можно без ущерба выкидывать некоторые буквы в смс. Ещё читал об исследовании Мэтта Дэвиса, что внутренние буквы в слове можно переставлять, потому что люди читают слова целиком, как единый образ (как иероглифы, в общем, а иероглифы со временем упрощаются). И знаю, что в некоторых языках (например, в церковно-славянском) гласные при записи тоже могут сокращаться.
Вначале попробовал удалять все гласные, но получалось нечитаемо. Думал оставлять только ударные, но тогда нужен словарь ударений, такую программу сложнее сделать. Поэтому стал добавлять простые исключения-эвристики. Конечные хорошо оставлять, потому что они несут информацию о склонении, и с ними фраза остаётся связной. Начальные редки, поэтому с ними слова лучше узнаются. «Не-» — слишком сильно важная для понимания смысла приставка, чтобы её можно было портить. Исключение для гласных между одинаковыми согласными — мне кажется, так лучше (не «склнние», а «склнение»). Необходимо было и что-то сделать с комбинациями дающими звук «й», они часты, а если их убирать, то и указания на звук «й» исчезает, читается хуже. Решил такие пары оставлять.
Вот так и придумал.
А мы-таки пользуемся таким алгоритмом уже более 2000 лет.
ОтветитьУдалить2 korey4ik: арабский или иврит?
ОтветитьУдалитьЭтот комментарий был удален автором.
ОтветитьУдалитьЭтот комментарий был удален администратором блога.
ОтветитьУдалить