2

我有一个数组,其中包含代表真值或假值的 1 或 0 值。例如

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

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

附言。我在 PHP 中工作

4

4 回答 4

6

这是我的建议:

$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 以便能够将其保存为字符串。

更新

相反的很简单:

$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. 将长二进制字符串拆分为数组
于 2013-02-22T11:39:27.770 回答
0

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

<?php

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

你会得到一个这样的字符串:

100101111

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

$string = '100101111';

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

?>

当然,您也可以将其设为小数并仅存储数字。这甚至比“原始”位还要短。

<?php

$dec = bindec( $string );

?>
于 2013-02-22T11:37:34.263 回答
0

打包和解怎么样

$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"
}
于 2013-02-22T13:25:12.353 回答
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;
}
于 2013-02-22T14:09:33.777 回答