Кодирование байтовых данных в цифры - PullRequest
8 голосов
/ 06 июня 2010

Существует ли распространенный метод кодирования и декодирования произвольных данных, чтобы закодированный конечный результат состоял только из цифр - например, base64_encode, но без букв?

Вымышленный пример:

$encoded = numbers_encode("Mary had a little lamb");

echo $encoded; // outputs e.g. 12238433742239423742322 (fictitious result)

$decoded = numbers_decode("12238433742239423742322");

echo $decoded; // outputs "Mary had a little lamb"

Ответы [ 4 ]

12 голосов
/ 04 августа 2010

Вы можете рассматривать строку (однобайтовый символ) как число с кодировкой base-256, где "\ x00" представляет 0, '' (пробел, то есть "\ x20") представляет 32 и так далее до "\ xFF" ", что представляет 255.

Представление только с номерами 0-9 можно выполнить, просто изменив представление на основание 10.

Обратите внимание, что "кодировка base64" на самом деле не является преобразованием базы . base64 разбивает входные данные на группы по 3 байта (24 бита) и выполняет базовое преобразование для этих групп индивидуально. Это хорошо работает, потому что число с 24 битами может быть представлено четырьмя цифрами в базе 64 (2 ^ 24 = 64 ^ 4).

Это более или менее то, что делает el.pescado - он разбивает входные данные на 8-битные куски, а затем преобразует число в базу 10. Однако этот метод имеет один недостаток относительно базы 64. кодирование - оно не корректно выравнивается по границе байта. Чтобы представить число с 8 битами (0-255 при отсутствии знака), нам нужно три цифры в базе 10. Однако самая левая цифра содержит меньше информации, чем остальные. Это может быть 0, 1 или 2 (для чисел без знака).

Цифра в базе 10 хранит биты log (10) / log (2). Независимо от того, какой размер порции вы выберете, вы никогда не сможете выровнять представления с 8-битными байтами (в смысле «выравнивания», которое я описал в предыдущем параграфе). Следовательно, наиболее компактное представление - это базовое преобразование (которое вы можете видеть, как если бы оно было «базовым кодированием» только с одним большим фрагментом).

Вот пример с bcmath .

bcscale(0);
function base256ToBase10(string $string) {
    //argument is little-endian
    $result = "0";
    for ($i = strlen($string)-1; $i >= 0; $i--) {
        $result = bcadd($result,
            bcmul(ord($string[$i]), bcpow(256, $i)));
    }
    return $result;
}
function base10ToBase256(string $number) {
    $result = "";
    $n = $number;
    do {
        $remainder = bcmod($n, 256);
        $n = bcdiv($n, 256);
        $result .= chr($remainder);
    } while ($n > 0);

    return $result;
}

Для

$string = "Mary had a little lamb";
$base10 = base256ToBase10($string);
echo $base10,"\n";
$base256 = base10ToBase256($base10);
echo $base256;

получаем

36826012939234118013885831603834892771924668323094861
Mary had a little lamb

Поскольку каждая цифра кодирует только log(10)/log(2)=~3.32193 бит, ожидается, что число будет иметь тенденцию быть 140% длиннее (не на 200% длиннее, как было бы с ответом el.pescado).

7 голосов
/ 06 июня 2010

Ну, это будет кодировка "base 8", а не Base 64. Это лучше знать как Octal.

Все, что делает Base64 - это конвертирует битовые потоки в 6-битные блоки (0-63) и назначает символ из набора символов из 64 символов. Octal использует 3 бита, 0-7. Таким образом, он МОЖЕТ использовать ABCDEFGH, но вместо этого использует 0-7. Вы не можете (легко) использовать 0-9, потому что 0-9 - это до 4 бит, но не полностью 4 бита. Вот что делает его паршивым кодированием для двоичных данных.

2 голосов
/ 06 июня 2010

Независимо от того, как вы кодируете, вы всегда окажетесь на меньшей базе.Может быть возможно уменьшить получающееся целое число немного меньше с некоторыми преобразованиями dechex (), но в конечном счете вы сохраните только несколько символов.Тем не менее, число действительно всплывает в тот момент, когда вы начинаете представлять многобайтовые символы с 0-9.

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

@el.pescado получает кредит за первую половину, но он бросил вызов читателю.Итак, я ответил (в основном потому, что хотел понять, что происходит).

function pekka_encode($s) {
    $out = '';
    for ($i=0;$i<strlen($s); $i++) {
        $out .= sprintf("%03d", ord($s[$i]));     
    }
    return $out;
}

function pekka_decode($s) {
    $out = '';
    for ($i=0;$i<strlen($s);$i+=3) {
        $out .= chr($s[$i].$s[$i+1].$s[$i+2]);
    }
    return $out;
}
2 голосов
/ 06 июня 2010

Очень простой пример - он представляет каждый входной байт в виде трехзначного десятичного числа:

function data2numbers ($data) {
    $out = "";
    for ($i = 0; $i < strlen ($data); $i++) {
        $out .= sprintf ("%03d", ord ($data[$i]));
    }
    return $out;
}

Недостатком является то, что он утраивает размер любых входных данных (каждый входной байт представлен как три выходных байта).

Функция декодирования оставлена ​​читателю в качестве упражнения;)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...