true または false の値を表す 1 または 0 の値を含む配列があります。例えば
array(1,0,0,1,0,1,1,1,1);
この配列を可能な限り短い文字列に圧縮/エンコードして、Cookie などのスペースに制約のある場所に格納できるようにしたいと考えています。また、後で再度デコードできるようにする必要もあります。どうすればいいですか?
ps。私はPHPで働いています
true または false の値を表す 1 または 0 の値を含む配列があります。例えば
array(1,0,0,1,0,1,1,1,1);
この配列を可能な限り短い文字列に圧縮/エンコードして、Cookie などのスペースに制約のある場所に格納できるようにしたいと考えています。また、後で再度デコードできるようにする必要もあります。どうすればいいですか?
ps。私はPHPで働いています
Here is my proposal:
$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=="
So you get each 8 characters (which in fact is a binary 0..255
), convert them to an integer, represent as an ASCII character, implode it to a string and convert to base64 to be able to save it as a string.
UPD:
the opposite is pretty straightforward:
$original = str_split(implode('', array_map(function($i) {
return decbin(ord($i));
}, str_split(base64_decode($compressed)))));
How exactly I wrote it (just in case anyone interesting how to write such unreadable and barely maintainable code):
I've written the $original = $compressed;
and started reversing the right part of this expression step by step:
Dont use serialize. Just make a string of it:
<?php
$string = implode( '', $array );
?>
You are left with an string like this:
100101111
If you want to have an array again, just access it like an array:
$string = '100101111';
echo $string[1]; // returns "0"
?>
Of course you could also make it a decimal and just store the number. That's even shorter then the "raw" bits.
<?php
$dec = bindec( $string );
?>
これが zerkms の回答に基づく私の解決策です。これは、10 進数を 2 進数に変換するときに先頭の 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;
}