Подтвердить что ты не робот

Что представляет собой наиболее эффективный двоичный код для кодирования текста?

Ближайшими соперниками, которых я смог найти, являются yEnc (2%) и ASCII85 (25% накладные расходы). Кажется, что некоторые проблемы вокруг yEnc связаны с тем, что он использует 8-битный набор символов. Это приводит к другой мысли: существует ли двоичная кодировка для текста на основе набора символов UTF-8?

4b9b3361

Ответ 1

Это действительно зависит от характера двоичных данных и ограничений, которые "текст" помещает на ваш вывод.

Прежде всего, если ваши двоичные данные не сжаты, попробуйте выполнить сжатие перед кодированием. Тогда мы можем предположить, что распределение 1/0 или отдельных байтов более или менее случайное.

Теперь: зачем вам текст? Как правило, это потому, что канал связи не проходит через все символы одинаково. например вам может потребоваться чистый текст ASCII, печатаемые символы которого варьируются от 0x20-0x7E. У вас есть 95 символов для игры. Каждый символ теоретически может кодировать log2 (95) ~ = 6,57 бит на символ. Легко определить преобразование, которое приближается довольно близко.

Но: что, если вам нужен символ разделителя? Теперь у вас есть только 94 символа и т.д. Таким образом, выбор кодировки действительно зависит от ваших требований.

Чтобы принять крайне глупый пример: если ваш канал передает все 256 символов без проблем, и вам не нужны какие-либо разделители, вы можете написать тривиальное преобразование, которое достигает 100% эффективности.:-) Как это сделать, остается как упражнение для читателя.

UTF-8 не является хорошим транспортом для произвольно закодированных двоичных данных. Он способен переносить значения 0x01-0x7F с накладными расходами 14%. Я не уверен, что 0x00 является законным; возможно нет. Но все, что выше 0x80, расширяется до нескольких байтов в UTF-8. Я бы рассматривал UTF-8 как ограниченный канал, который пропускает 0x01-0x7F или 126 уникальных символов. Если вам не нужны дериметры, вы можете передать 6,98 бит на символ.

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

Предположим, что в алфавите 95 символов. Теперь: некоторые из этих символов будут представлять 6 бит, а некоторые будут представлять 7 бит. Если у нас есть 6-битные символы и B 7-битные символы, то:

A + B = 95 (общее количество символов) 2A + B = 128 (общее количество 7-битных префиксов, которые можно сделать. Вы можете запустить 2 префикса с 6-битным символом или с 7-битным символом.)

Решая систему, вы получаете: A = 33, B = 62. Теперь вы создаете таблицу символов:

Необработанный кодированный
000000 0000000
000001 0000001
...
100000 0100000
1000010 0100001
1000011 0100010
...
1111110 1011101
1111111 1011110

Для кодирования сначала смените 6 бит ввода. Если эти шесть бит больше или равны 100001, тогда сдвиньте другой бит. Затем найдите соответствующий 7-битный выходной код, переведите его в нужное место и отправьте. Вы будете перемещать 6 или 7 бит ввода на каждую итерацию.

Чтобы декодировать, принять байт и перевести на исходный код вывода. Если исходный код меньше 0100001, тогда сдвиньте соответствующие 6 бит на ваш выход. В противном случае сдвиньте соответствующие 7 бит на ваш выход. Вы будете генерировать 6-7 бит вывода каждой итерации.

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

Ответ 2

Короткий ответ будет: Нет, до сих пор нет.

Я столкнулся с проблемой кодирования как можно большей информации в строке JSON, что означает UTF-8 без управляющих символов, обратного слэша и кавычек.

Я вышел и исследовал, сколько бит вы можете сжать в действительные байты UTF-8. Я не согласен с ответами на то, что UTF-8 приносит слишком много накладных расходов. Это не так.

Если вы принимаете во внимание только однобайтовые последовательности, он столь же мощный, как и стандартный ASCII. Значение 7 бит на байт. Но если вы вычеркнете все специальные символы, вы останетесь с чем-то вроде Ascii85.

Но в более высоких плоскостях меньше управляющих символов. Поэтому, если вы используете 6-байтовые фрагменты, вы сможете кодировать 5 байт на кусок. На выходе вы получите любую комбинацию символов UTF-8 любой длины (от 1 до 6 байтов).

Это даст вам лучший результат, чем Ascii85: 5/6 вместо 4/5, 83% эффективности вместо 80%. Теоретически это будет еще лучше с более высокой длиной блока: около 84% при 19-байтовых кусках.

По-моему, процесс кодирования становится слишком сложным, в то время как он обеспечивает очень небольшую прибыль. Итак, Ascii85 или какая-то модифицированная версия (теперь я смотрю Z85).

Ответ 3

Согласно Википедии

BasE91 создает кратчайший обычный ASCII-вывод для сжатого 8-битного двоичного ввода.

Ответ 4

Я искал наиболее эффективную двоичную кодировку в прошлом году. Я сам себе понял, что компактность - не единственный критерий. Самое главное, где вы можете использовать закодированную строку. Например, yEnc имеет 2% служебных данных, но это 8-битное кодирование, поэтому его использование очень ограничено.

Мой выбор Z85. Он имеет приемлемые 25% -ные накладные расходы, и закодированная строка может использоваться почти везде: XML, JSON, исходный код и т.д. Подробнее см. В Z85 спецификация.

Наконец, я написал Z85 library в C/С++ и использовал его в процессе производства.

Ответ 5

Похоже, у тебя уже есть ответ, Марк. UTF-8 не полезен в качестве двоичного кодирования, поскольку любой символ UTF-8, превышающий один байт, имеет более 25% служебных данных даже для хранения текста (2 или более бит на каждый байт). Base64 кодировки уже лучше этого.

Ответ 6

Рядом с теми, которые перечислены на Wikipedia, есть Bommanews:

B-News (или bommanews) был разработан, чтобы поднять вес служебных данных, присущих кодировке UUEncode и Base64: он использует новый метод кодирования для заполнения двоичных данных в текстовых сообщениях. Этот метод использует больше ресурсов ЦП, но ему удается снизить потери с примерно 40% для UUEncode до 3,5% (десятичная точка между этими цифрами не является грязью на вашем мониторе), но при этом все еще избегает использования управляющих кодов ANSI в сообщении тела.

Это сопоставимо с yEnc: source

yEnc менее интенсивно потребляет процессор, чем B-News, и достигает примерно того же низкого уровня накладных расходов, но не избегает использования всех управляющих кодов, он просто оставляет те, которые (экспериментально) наблюдались как нежелательные эффекты на некоторых серверах, что означает, что он несколько меньше RFC, чем B-News.

Ответ 7

В настоящее время base91 - лучшая кодировка, если вы ограничены только символами ASCII и не хотите использовать непечатаемые символы. Он также обладает преимуществом молниеносной скорости кодирования/декодирования, поскольку может использоваться таблица поиска, в отличие от base85, который должен быть декодирован с использованием медленных делений

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

Base-122 Кодировка

Кодирование Base-122 принимает куски по семь бит входных данных за раз. Если блок отображается на допустимый символ, он кодируется однобайтовым символом UTF-8: 0xxxxxxx. Если блок будет отображаться с недопустимым символом, мы вместо этого используем двухбайтовый символ UTF-8: 110xxxxx 10xxxxxx. Поскольку существует только шесть недопустимых кодовых точек, мы можем различить их только тремя битами. Обозначая эти биты как sss мы получаем формат: 110sssxx 10xxxxxx. Оставшиеся восемь битов могут, казалось бы, кодировать больше входных данных. К сожалению, двухбайтовые символы UTF-8, представляющие кодовые точки менее 0x80, недопустимы. Браузеры будут анализировать недопустимые символы UTF-8 в символы ошибок. Простой способ применения кодовых точек, больших 0x80, заключается в использовании формата 110sss1x 10xxxxxx, эквивалентного побитовому ИЛИ с 0x80 (это, вероятно, можно улучшить, см. §4). Рисунок 3 суммирует полное кодирование base-122.

Base-122 encoding scheme

http://blog.kevinalbs.com/base122

Ответ 8

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

Ответ 9

Если вы ищете эффективную кодировку для больших алфавитов, вы можете попробовать использовать escape. И escapeless252, и yEnc имеют накладные расходы на 1,6%, но с первым оно исправлено и известно заранее, а с последним оно фактически колеблется от 0 до 100% в зависимости от распределения байтов.

Ответ 10

Недавно мне пришлось кодировать двоичный файл как ascii, и это то, с чем я столкнулся. Я не знаю, является ли это наиболее эффективным (возможно, нет), но это просто и быстро. В принципе, я кодирую байт как шестнадцатеричный, но вместо использования базового набора (0-9, A-F) я использую (a-p). Поскольку набор является непрерывным, он не требует поиска в таблице.

//buff is a unsigned character array containing the binary data
//N is the number of bytes to be encoded 
string simple_encode(unsigned char *buff, int N)
{
    string sEncode = "";
    for(int i = 0; i<N; i++)
    {
        sEncode += (97 + (buff[i] >> 4));
        sEncode += (97 + (buff[i] & 0x0F));
    }
    return sEncode;
}

//sbuff is a string containing the encoded ascii data
//szDecoded is an unsigned char array that has been allocated to 1/2 
//the length of sbuff
//N is an integer pointer and returns the number of converted bytes
void simple_decode(string sbuff, unsigned char *szDecode, int *N)
{
    *N = sbuff.length()/2;
    for(int i=0; i < *N; i++)
    {
        szDecode[i] = ((sbuff.at(2*i)-97) << 4) + (sbuff.at(2*i+1)-97);
    }
}