Резюме
Это решение позволит вам использовать любой из большого количества языков, включая произносимую ерунду, с настраиваемой эффективностью. Вы даже можете создать что-то, что выглядит грамматически правильным, но бессмысленным английским или французским (или, что еще хуже, что-то, что перемещается между ними, как пьяный полиглот). Основная идея состоит в том, чтобы использовать ваши данные для непрерывного выбора путей из контекстно-свободной грамматики, пока у вас не закончатся данные.
Подробнее
Добавить строку в конец вашего ввода, которая не встречается нигде внутри него («Это конец моего ввода, большое спасибо» вряд ли будет происходить в строке зашифрованного текста, для Пример.) Вы можете сделать это без строки, но это облегчает.
Рассматривайте ваш вход как один очень длинный целочисленный кодированный младший бит первым. Очевидно, что ваша машина не сможет обрабатывать такое большое целое число, каждый раз, когда у вас будет нулевой старший байт, просто удалите значения из следующего байта из вашего файла и умножьте их на.
Создайте свой язык как контекстно-свободную грамматику . Чтобы не забыть, что такое кодировка, вы можете распечатать ее в конце своей книги. Избегайте двусмысленности. Если ваша грамматика неоднозначна, вы не сможете расшифровать. Это не сложно, по сути, не используйте один и тот же терминал в двух местах, убедитесь, что объединение двух терминалов не может сделать другой терминал, и убедитесь, что при чтении выходных данных вы можете сказать, куда вы помещаете символы форматирования.
Теперь, чтобы взять целое число и превратить его в язык, используйте следующий псевдокод, который использует n, чтобы выбрать, какую продукцию взять.
cur=grammar.root (cur is a list of tokens)
n=my input as one big integer
while(n > 0 || cur != grammar root){
if (cur.first.isTerminalSymbol) {
output cur.first
cur.pop_first
if(cur.isEmpty){
cur = grammar root
}
}else{
p = grammar[cur.first].number of productions
t = n mod p // t = low order digit base p
n = n div p // Shift left in base p
cur.pop_first
cur.push_first( grammar[cur.first].productionNumber[t] )
}
}
Для декодирования вы используете стандартный генератор синтаксического анализатора, такой как GNU bison , который также должен помочь вам избежать создания неоднозначной грамматики.
Запустить парсер на входе. Теперь начните с n с 0. Вы можете получить производственный номер каждый раз, ссылаясь на синтаксическое дерево, сгенерированное синтаксическим анализатором. Затем умножьте n на количество произведений и добавьте номер производства, чтобы получить n после этого конкретного ввода. Когда вы заполните младший байт машинного слова, сдвиньте его в декодированный файл. Когда вы прочитаете свою уникальную фразу, прекратите расшифровку.
Пример 1
Это будет понятнее с примером или тремя.
Мой пример простого языка следующий (нетерминалы пишутся с заглавной буквы). Обратите внимание, что из-за большого размера терминалов по сравнению с их глубиной дерева это не очень эффективно, но я думаю, что наличие большего количества терминалов или их укорочение может дать вам любую эффективность, которую вы хотите (вплоть до количества бит, потраченных впустую на символ используя n бит на символ).
- S -> __capital существительное I-глагол Punct | __capital существительное T-глагол существительное пункт
- Существительное -> Джо | Салли | пятно | машина | печенье | шланг
- I-Verb -> работает | жизни | прыжки | летает
- T-Verb -> перепрыгивает | ест | растет | спины
- Пункт ->. | ! |
Вы можете так же легко сделать это с помощью слогов, как расширение глаголов и существительных. Вы также можете включить в свой род существительные и глагольные фразы, чтобы иметь прилагательные и т. Д. Возможно, вам также понадобятся символы абзацев и глав, которые разбиваются на соответствующие подразделения с форматированием. Количество альтернативных вариантов выбора на определенном уровне дерева определяет среднее количество битов, закодированных каждым символом. __capital - это пример символа форматирования, который при выводе использует заглавные буквы для следующего слова.
Итак, представьте, что мой ввод становится числом 77. Тогда я бы закодировал его следующим образом:
S идет к двум вещам. 77% 2 = 1. Остаток 77/2 = 38.
Теперь наш номер 38, и мы расширяем __capital, Существительное, T-глагол, Существительное, Пункту
Первое слово - __capital, который является конечным символом. Вывод __capital (настройка процедуры печати для прописного следующего слова).
Теперь расширяем существительное. Существительное имеет 6 вариантов. 38% 6 = 2. 38/6 = 6. Выбираем спот
Теперь расширяющееся пятно, T-глагол, существительное, пункт. Спот-терминал. Выходной спот. Принтер, находящийся в режиме прописной буквы, записывает «Spot» в выходной файл.
Теперь расширяем T-Verb. Наш номер 6. Т-глагол имеет 4 варианта. 6% 4 = 2. 6/4 = 1. Поэтому мы выбираем «растет». На следующем шаге мы вырастем до нашего файла, так как это терминал.
Теперь расширяем существительное, пункт. Существительное имеет 6 вариантов. Наше число равно 1. 1% 6 = 1 1/6 = 0. Поэтому мы выбираем «Салли», который выводится на следующем шаге.
Наконец, мы расширяем пункт, который имеет 3 варианта. Наше число равно 0 (и останется таким же навсегда - вот почему вы добавляете строку конца текста к концу ввода, иначе ваше декодирование закончилось бы бесконечной строкой нулей.) Мы выбираем «.», который выводится.
Теперь текущая строка для раскрытия пуста, поэтому мы возвращаем ее к корню "S". Но так как n равно 0, алгоритм завершается.
Таким образом, 77 стал "Пятно растет Салли".
Пример 2
Вещи станут более эффективными, если я заменю свои терминалы на:
- I-Verb IVS _space | IVS I-Verb
- IVS IVSS гласная
- IVSS w | г
- гласная а | е | я | о | ты | у
- T-Verb TVS _space | TVS T-Verb
- TVS TVSS гласная
- TVSS p | s
- Существительное NS _space | NS
- NS NSS Vowel
- NSS j | V
77 дает "Джо папа джа." в этой кодировке (и действительно кодируется только «Джо» и тем фактом, что папа имеет 2 слога. Дополнительный будет очень малая доля в любом файле длины книги.)
Пример 3
Ваш пример «08F734F7» будет «1000111101110011010011110111» в двоичном формате, то есть «1110111100101100111011110001» при обращении, то есть 250793713 в десятичном виде.
Если я пройду через более компактную грамматику, я получу:
25079713 % 2 = 1 n=125396856, S-> __capital Noun T-Verb Noun Punct
125396856 % 2 = 0 n=62698428, Noun->NS _space-> NSS Vowel _space
62698428 % 2 = 0 n=31349214, NSS->j
31349214 % 6 = 0 n=5224869, Vowel->a
5224869 % 2 = 1 n=2612434, T-Verb->TVS T-Verb->TVSS Vowel T-Verb
2612434 % 2 = 0 n=1306217, TVSS->p
1306217 % 6 = 5 n=217702, Vowel->y
217702 % 2 = 0 n=108851, T-Verb->TVSS Vowel _space
108851 % 2 = 1 n=54425, TVSS->s
54425 % 6 = 5 n=9070, Vowel->y
9070 % 2 = 0 n=4535, Noun->NSS Vowel _space
4535 % 2 = 1 n=2267 NSS->v
2267 % 6 = 5 n=377 Vowel->y
377 % 3 = 2 n=125 Punct->?
125 % 2 = 1 n=62 S->__capital Noun T-Verb Noun Punct
62 % 2 = 0 n=31 Noun->NSS Vowel _space
31 % 2 = 1 n=15 NSS->v
15 % 6 = 3 n=2 Vowel->o
2 % 2 = 0 n=1 T-Verb->TVSS Vowel _space
1 % 2 = 1 n=0 TVSS->p
n=0 Vowel _space Noun Punct -> "a ja."
Это дает:
"Ja pysy vy? Vo pa ja." от 08F734F7
(обратите внимание, что моя процедура печати удаляет пробелы перед пунктуацией)