一尘不染

将字节数据编码为数字

algorithm

有没有一种通用的方法来编码和解码任意数据,以便编码的最终结果仅由数字组成-像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"

阅读 234

收藏
2020-07-28

共1个答案

一尘不染

您可以将(单字节字符)字符串视为以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的编码,此技术有一个缺点–它不能与基数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
玛丽有只小羊羔

由于每个数字仅编码log(10)/log(2)=~3.32193位,因此期望该数字趋向于长140%(而不是长200%,这与el.pescado的答案一样)。

2020-07-28