【问题标题】:Encode integer sequence to smallest string php将整数序列编码为最小的字符串php
【发布时间】:2016-08-06 00:48:03
【问题描述】:

我有一长串数字,它们都小于 5,我想将其编码为字符串以尽可能减少字符串长度,但保持检索原始数字的能力。

我想过换更高的基数:

<?php
$str = '2222342022223411112203302222232222122221230222';
$baseEncodeFrom = 5;
$baseEncodeTo = 36;
echo base_convert(base_convert($str,$baseEncodeFrom,$baseEncodeTo),$baseEncodeTo,$baseEncodeFrom);
//2222342022223411112203413300041330121304332023

但是,正如 php 参考中提到的,大数字会丢失精度,因此会丢失原始字符串。有没有办法减少原始字符串长度并且仍然能够检索原始字符串?

【问题讨论】:

  • 也许是个愚蠢的问题,但你想减少字符串长度的原因是什么?

标签: php encoding


【解决方案1】:

您需要研究不同的压缩方法和算法,因为您可以压缩的程度取决于算法。例如,这是一个非常幼稚且可能效率低下的算法。

<?php

$str = '2222342022223411112203302222232222122221230222';
echo $str . "\r\n";

$values = [

];

$lastChar = null;
$value = [];
foreach (str_split($str) as $character) {
    if ($lastChar === null) {
        $value = ['number' => $character, 'count' => 1];
        $lastChar = $character;
        continue;
    }

    if ($lastChar !== $character) {
        $values[] = $value;
        $value = ['number' => $character, 'count' => 0];
    }

    $value['count']++;
    $lastChar = $character;
}

$values[] = $value;

function combine($a, $b) {
    return str_pad(base_convert($a, 10, 2), 5, "0", STR_PAD_LEFT) . str_pad(base_convert($b, 10, 2), 3, "0", STR_PAD_LEFT);
}

function compressValue($value) {
    $return = '';

    if ($value['count'] > 8) {
        $return .= compressValue(['number' => $value['number'], 'count' => $value['count'] - 8]);
        $value['count'] = $value['count'] % 8;
    }

    $return .= combine($value['count'], $value['number']);

    return $return;
};

$values = array_map('compressValue', $values);
$values = join("", $values);
$values = str_split($values, 8);
$values = array_map(function ($value) {
    $ord = chr(bindec($value));
    return $ord;
}, $values);
$values = join("", $values);
echo $values . "\r\n";

echo strlen($values) . "\r\n";
echo strlen($str) . "\r\n";

输出...很多不可读的字符。那有一个23的strlen!比原来的 46 还短!

那么它有什么作用呢?它接受字符串,并说“有 4 个 2,然后是 1x3、1x4、1x2 1x0、4x2”等等。然后它把它们变成一个组合的二进制文件。我们将使每个 8 位二进制文​​件成为一种长度的字母。所以 4x2 因为 00100 。 010 由于所有数字都小于 5,因此我们使用二进制的最后 3 位作为数字,其他 5 位作为计数。如果超过 31(我们可以存储在 5 位中的最大计数),我们将把其余的存储在下一个字节中。

然后,我们有一个很长的二进制字符串,所以我们将它转​​换为十六进制。

所以,要转换回来,我们可以从十六进制转换为二进制,然后将其拆分为 8 位数字的块,并取每个块的前 5 个,将其转换为 dec 并取接下来的 3 个块,将其转换为 dec,然后按照第一个 dec 中的次数重复第二个 dec

话虽如此,这只是我第一次尝试压缩算法,我对它们了解不多。因此,如果您想通过 Google 查找更多信息,并研究不同的算法,您可能会找到更有效的方法。我的程序中可能也有错误,这是一个简短的概念证明

解码它的代码是

$values = str_split($values);
$values = array_map(function ($value) {
    return str_pad(decbin(ord($value)), 8, "0", STR_PAD_LEFT);
}, $values);

$values = array_map(function ($value) {
    $count = substr($value, 0, 5);
    $number = substr($value, 5, 3);

    $count = base_convert($count, 2, 10);
    $number = base_convert($number, 2, 10);

    return str_repeat($number, $count);
}, $values);

echo join("", $values);

【讨论】:

    猜你喜欢
    • 2020-07-05
    • 1970-01-01
    • 1970-01-01
    • 2020-03-22
    • 2018-04-14
    • 2012-07-09
    • 2022-08-16
    • 1970-01-01
    相关资源
    最近更新 更多