PHP将比特数组压缩成最短的字符串

时间:2013-02-22 11:32:00

标签: php arrays encoding compression

我有一个包含值1或0的数组,表示true或false值。 e.g。

array(1,0,0,1,0,1,1,1,1);

我希望将此数组压缩/编码为可能的最短字符串,以便将其存储在空间受限的位置(如cookie)中。它还需要能够在以后再次解码。我该怎么做?

PS。我在PHP工作

4 个答案:

答案 0 :(得分:5)

以下是我的建议:

$a = array(1,0,0,1,0,1,1,1,1,1,0,0,1,0,1,1,1,1,1,0,0,1,0,1,1,1,1);

$compressed = base64_encode(implode('', array_map(function($i) {
    return chr(bindec(implode('', $i)));
}, array_chunk($a, 8))));

var_dump($compressed); // string(8) "l8vlBw=="

所以你得到每8个字符(实际上是二进制0..255),将它们转换为整数,表示为ASCII字符,将其内嵌到字符串并转换为base64以便能够保存它作为一个字符串。

<强> UPD

相反的情况非常简单:

$original = str_split(implode('', array_map(function($i) {
    return decbin(ord($i));
}, str_split(base64_decode($compressed)))));

我是如何编写它的(以防万一有人如何编写这样难以理解且几乎无法维护的代码):

我写了$original = $compressed;并开始逐步颠倒这个表达式的右边部分:

  1. 从base64解码为二进制字符串
  2. 将其拆分为数组
  3. 将每个字符转换为ASCII码
  4. 将十进制ASCII码转换为二进制
  5. 将所有二进制数加入一个
  6. 将长二进制字符串拆分为数组

答案 1 :(得分:0)

不要使用序列化。只需制作一个字符串:

<?php

$string = implode( '', $array );
?>

你留下了这样的字符串:

100101111

如果您想再次拥有一个数组,只需像数组一样访问它:     

$string = '100101111';

echo $string[1]; // returns "0"

?>

当然你也可以把它设为小数,然后存储数字。这甚至比“原始”位短。

<?php

$dec = bindec( $string );

?>

答案 2 :(得分:0)

packunpack

怎么样?
$arr = array(1,1,1,1,0,0,1,1,0,1,0,0,1,1,0,0,1,1,1,1);
$str = implode($arr);
$res = pack("h*", $str);
var_dump($res);
$rev = unpack("h*", $res);
var_dump($rev);

<强>输出:

string(10) # Not visible here
array(1) {
  [1]=>
  string(20) "11110011010011001111"
}

答案 3 :(得分:0)

这是我基于zerkms答案的解决方案,它处理将小数转换回二进制时丢失前导0的问题。

function compressBitArray(array $bitArray){
    $byteChunks = array_chunk($bitArray, 8);

    $asciiString = implode('', array_map(function($i) {
        return chr(bindec(implode('', $i)));
    },$byteChunks));   

    $encoded = base64_encode($asciiString).'#'.count($bitArray);
    return $encoded;
}


//decode
function decompressBitArray($compressedString){
    //extract origional length of the string
    $parts = explode('#',$compressedString);
    $origLength = $parts[1];

    $asciiChars = str_split(base64_decode($parts[0]));
    $bitStrings = array_map(function($i) {
        return decbin(ord($i));
    }, $asciiChars);

    //pad lost leading 0's
    for($i = 0; $i < count($bitStrings); $i++){
        if($i == count($bitStrings)-1){
            $toPad = strlen($bitStrings[$i]) + ($origLength - strlen(implode('', $bitStrings)));
            $bitStrings[$i] = str_pad($bitStrings[$i], $toPad, '0', STR_PAD_LEFT);
        }else{
            if(strlen($bitStrings[$i]) < 8){
                $bitStrings[$i] = str_pad($bitStrings[$i], 8, '0', STR_PAD_LEFT);
            }
        }
    }

    $bitArray = str_split(implode('', $bitStrings));
    return $bitArray;
}