Який тип кодування можна використовувати для скорочення рядка?


13

Мене цікавить кодування рядка, який я маю, і мені цікаво, чи є такий тип кодування, який може бути використаний, що буде включати лише альфа та числові символи, і бажано скоротити кількість символів, необхідних для представлення рядка.

До сих пір я розглядав використання кодування Base64 для цього, але, здається, збільшує мою рядок і іноді включає в себе те, ==чого я хотів би уникнути. Приклад:

назва тесту | 120101

стає

dGVzdCBuYW1lfDEyMDEwMQ ==

який містить від 16 до 24 символів і включає не буквено-цифрові.

Хтось знає про інший тип кодування, який я міг би використовувати, щоб досягти моїх вимог? Бонусні бали, якщо він або вбудований в .NET рамку, або існує стороння бібліотека, яка виконуватиме кодування.


1
не можна використовувати втрати, менші за стиснення, як кодування Хаффмана !! Вони ідеально підходять для текстів ... але тоді, коли ви отримаєте кінець, ви дійсно повинні знати про цю мутацію, яку ви зробили для повернення тексту.

6
Ви описуєте стиснення, а не кодування
Енді Сміт

@Andrew - Гаразд, якісь пропозиції?
Ейб Місслер

Відповіді:


30

Остаточний '=' або '==' в Base64 є лише для того, щоб кількість символів була кратною 4. Ви можете його видалити, оскільки ви завжди зможете повернути його згодом. Зауважте, що Base64 так називається, оскільки він використовує 64 різних символи. Великі літери, малі літери та цифри - це 62. Отже, Base64 також використовує '/' і '+', що може або не відповідає вашому рахунку.

На загальних підставах, якщо ви хочете кодувати довільні послідовності байтів в буквено-цифрові символи, обов'язково десь є розширення довжини, оскільки для байта є 256 можливих значень, і лише 62 буквено-цифрових символів. Іноді його називають принципом голубого отвору . Схема кодування повинна мати середнє продовження довжини факторного журналу 256 / log 62 = 1.344 (середнє значення для всіх послідовностей байтів); в іншому випадку це означає, що деяких голубів десь придушують до смерті, і ви не повернете їх назад без пошкоджень (а це означає: дві чіткі рядки закодовані в один і той же, тому розшифровка не може надійно працювати).

Тепер цілком можливо, що ваші рядки - це не зовсім «послідовності рівномірно випадкових байтів»; ваші рядки мають певне значення, що означає, що найбільш можлива послідовність байтів не відбудеться, оскільки вони безглузді. Виходячи з цього, ви, ймовірно, можете розробити схему кодування, яка матиме менше розширення довжини, ніж загальна Base64 (або Base62, якщо вам потрібно дотримуватися суворих буквено-цифрових символів). Це стиснення даних без втрат . Він працює над чітко визначеною ймовірнісною моделлю того, що може виявитися вхідним.

Резюме: загальна схема для кодування рядків в буквено - цифрові послідовності , такі , що немає або мало Подовження ніколи не відбувається, не можуть існувати; це математична неможливість. Конкретна схема спеціально для виду вхідного рядка , яку ви очікуєте , ймовірно , може існувати (але так як ви не говорите , які рядки ви можете зіткнутися, ніхто НЕ може допомогти вам в цьому).


1
+1, відмінне пояснення. Я не знав про =/ ==пов’язане з тим, що тривалість повинна бути кратною 4. Можливо, я зможу обійти це для своїх потреб
Abe Miessler

Зауважте, це передбачає брак голубів. У Unicode багато букв. Нам дійсно потрібно краще розуміння реальної проблеми.
MSalters

@Тому як ви обчислили коефіцієнт розширення середньої довжини за допомогою поділу журналу? На основі діаграми в en.wikipedia.org/wiki/Base64 цілком має інтуїтивний сенс, що для кожного незашифрованого символу потрібно 4/3 символів у Base64. Цікаво, як ти дійшов такого ж висновку з математикою ... дякую :)
Джонатан Лін

Моє погане, дурне запитання. log (256) = 8 біт, log (64) = 6 біт, отже, для Base64 коефіцієнт становить 8/6 = 4/3 = 1,333. Ура.
Джонатан Лін

4

Перекодування символів, як правило, робиться, коли приймаюча система не може їх обробити. Наприклад, BASE64 представляє дані, використовуючи 6 бітів (2 6 , отже 64) символів для представлення довших послідовностей даних (іноді з'являється "==" в кінці є заміщенням для вирівнювання). Це тому, що у вашому файлі зображень в електронній пошті може бути 0xFE в ньому, і ваш поштовий сервер буде незадоволено передавати це (або будь-який інший традиційно недрукувальний символ).

Не існує кодування, яке "зменшує розмір". Кодування - це просто зіставлення бітів із символом, який вони представляють. Однак, ASCII - це 7-бітний набір символів (кодування), який часто зберігається у 8 бітах простору. Якщо ви обмежите діапазони, які ви приймаєте, ви також можете вилучити контрольні символи.

Використання цього методу означає, що вам потрібно виписати речі на рівні бітів, а також він грає трохи пекла зі швидкістю та інструкціями машини, оскільки всі сучасні машини мають вирівнювання, кратні 8 біт. Наприклад, чому Unicode - це UTF-8, UTF-16 та UTF-32.

Якщо ви робите це для безпеки (саме тому ви розмістили його на Security.SE, правда?), Просто відфільтруйте речі та зберігайте їх у звичайному режимі. Якщо ви робите це для економії місця, подумайте, чи варто зайвий код та уповільнений час доступу (оскільки більшість записів перетинають межі адреси) варто економії місця.

До речі, наступний фрагмент курсу CS, де нам довелося перетворити ASCII з 8-бітового сховища до 7-бітного:

    memset(dest,0x00,8);
    memcpy(dest, source, length);

    for (int i = 0; i < 8; i++) {
            if (dest[i] & 0x80) {
                    fprintf(stderr, "%s: %s\n", dest, "Illegal byte sequence");
                    exit(EILSEQ);
            }
    }

    dest[0] = 0x7F & dest[0] | 0x80 & dest[1] << 7;
    dest[1] = 0x3F & dest[1] >> 1 | 0xC0 & dest[2] << 6;
    dest[2] = 0x1F & dest[2] >> 2 | 0xE0 & dest[3] << 5;
    dest[3] = 0x0F & dest[3] >> 3 | 0xF0 & dest[4] << 4;
    dest[4] = 0x07 & dest[4] >> 4 | 0xF8 & dest[5] << 3;
    dest[5] = 0x03 & dest[5] >> 5 | 0xFC & dest[6] << 2;
    dest[6] = 0x01 & dest[6] >> 6 | 0xFE & dest[7] << 1;
    dest[7] = 0x00; //Clearing out

2

Ви можете стиснути дані, наприклад, gzip, bzip2 або lzma, а потім пропустити через base64 для обмеження використовуваного набору символів. Це вигідно лише для більших рядків сотень байт і більше.


1

чому б не використовувати стиснення LZ? це може бути гідним способом стиснення струни, але було б більш ефективним у випадку довгих струн. Як довго триває цільовий рядок, який потрібно кодувати?


Як компресія LZ порівнюється з gzip або bzip2, згаданими у пропозиції attir?
NoChance

gzip побудований на LZ та Huffman Coding. детальніше на LZ en.wikipedia.org/wiki/LZ77
А.Рашад
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.