Как кодировать и декодировать Base91
- Введите или вставьте текст в поле Ввод · Текст. Закодированная строка появится в поле Результат · basE91.
- Для двоичных данных выберите в поле Из вариант Hex или Base64 и вставьте данные в этом виде.
- Для декодирования нажмите basE91 → Текст в переключателе направления. Переносы строк во входных данных игнорируются; любой другой символ вне алфавита останавливает декодирование с указанием позиции.
- Скопируйте результат (Скопировать результат) или сохраните его файлом (Скачать). Декодированные двоичные данные сохраняйте кнопкой Сохранить байты.
Как работает basE91
basE91 опубликовал Йоахим Хенке (Joachim Henke). Base64 отображает каждые 6 бит в один символ. basE91 вместо этого собирает биты входа в очередь и берёт по 13 бит за раз. Двумя символами можно записать 91 × 91 = 8281 значение, чуть больше, чем 8192, которые нужны для 13 бит. Запас уходит на оптимизацию: когда следующие 13 бит дают значение 88 или меньше, кодировщик берёт 14 бит и всё равно пишет два символа.
Из-за этого длина результата зависит от содержимого. На случайных данных 14-битные группы редки (меньше 1,1% групп), поэтому накладные расходы близки к 16/13, около 23%. Данные с большим числом нулевых битов упаковываются лучше: 1000 нулевых байтов кодируются в 1143 символа, это 14% накладных расходов.
| Вход | basE91 | Base64 |
|---|---|---|
test | fPNKd | dGVzdA== |
Hello | >OwJh>A | SGVsbG8= |
Hello World! | >OwJh>Io0Tv!8PE | SGVsbG8gV29ybGQh |
| 4 нулевых байта | AAAAA | AAAAAA== |
| 1000 случайных байтов | около 1230 символов | 1336 символов |
У групп переменной длины есть побочный эффект: фиксированного размера блока нет, поэтому нельзя декодировать с середины строки или разрезать её в произвольном месте. Base64 можно резать по любой границе, кратной 4 символам.
Алфавит и где он мешает
Алфавит basE91 состоит из A–Z, a–z, 0–9 и вот этих 29 символов:
!#$%&()*+,./:;<=>?@[]^_`{|}~"
В нём нет пробела, ', - и \. Пробел и ' создают проблемы в shell и строках в кавычках, а \ почти везде служит escape-символом. Двойная кавычка всё же осталась, как и <, > и &, поэтому basE91 внутри JSON, HTML или XML нужно экранировать, и экранирование съедает часть выигрыша перед Base64. Лучше всего он работает там, где принимается любой печатный ASCII: в текстовом файле, в аргументе shell в одинарных кавычках или в поле протокола, которое пропускает любые байты.
Кодировщик basE91 на Python
В стандартной библиотеке basE91 нет. Алгоритм Хенке достаточно короткий, чтобы привести его целиком:
ALPHABET = ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
"0123456789!#$%&()*+,./:;<=>?@[]^_`{|}~\"")
def b91encode(data: bytes) -> str:
out, queue, nbits = [], 0, 0
for byte in data:
queue |= byte << nbits
nbits += 8
if nbits > 13:
value = queue & 8191
if value > 88:
queue >>= 13
nbits -= 13
else:
value = queue & 16383
queue >>= 14
nbits -= 14
out += ALPHABET[value % 91], ALPHABET[value // 91]
if nbits:
out.append(ALPHABET[queue % 91])
if nbits > 7 or queue > 90:
out.append(ALPHABET[queue // 91])
return "".join(out)
b91encode(b"test") # 'fPNKd'
Для любого входа он даёт тот же результат, что и эта страница. Про работу с байтами в Python читайте на странице про Python.
Когда выбирать Base91
Берите basE91, когда на счету каждый байт результата, а канал принимает почти любой печатный ASCII: компактные логи или текстовые поля с жёстким ограничением длины. Для всего, что идёт в JSON, URL, HTML или почту, Base64 надёжнее и почти так же короток, а Ascii85 стандартизирован в PDF и PostScript, если нужны 25% накладных расходов с фиксированными блоками.
Вопросы и ответы
Какие символы использует Base91?
Все 95 печатных символов ASCII, кроме пробела, апострофа ', дефиса - и обратного слеша \. Остаются буквы, цифры и 29 знаков препинания, включая двойную кавычку.
Base91 компактнее Base85?
Немного. Случайные данные вырастают в basE91 примерно на 23%, а в Base85 – ровно на 25%; 100 000 случайных байтов здесь превратились в 122 976 символов против 125 000 в Ascii85. Данные с длинными сериями нулевых байтов сжимаются ещё сильнее, примерно до 14% накладных расходов.
Почему Base91 не так распространён?
У него нет RFC, в результате встречаются " и другие символы, которые нужно экранировать в JSON, shell и HTML, а группы переменной длины делают его медленнее и сложнее в реализации, чем Base64. Несколько сэкономленных процентов редко того стоят.
Можно ли декодировать Base91 из другой библиотеки?
Только если она использует алфавит и порядок битов basE91 Хенке, как большинство библиотек. Некоторые поставляют собственные алфавиты Base91; их результат декодируется здесь без ошибки, но байты получаются неверные.