这是一个完整的正长整数压缩和解压缩代码,基于 h3n 使用 1 个字节代表 2 个字符的想法,谢谢!它使用 15 位数字系统:从 0000 到 1110 二进制和 1111 (0xF) 作为分隔符。
压缩:
public List<byte> EncodeNumbers(List<long> input)
{
List<byte> bytes = new List<byte>();
int bytes_i = 0;
for (int a = 0; a < input.Count; a++)
{
int buffer_i = 65;
byte[] buffer = new byte[buffer_i];
while (input[a] > 0)
{
buffer[--buffer_i] = (byte)(input[a] %15);
input[a] /= 15;
}
for (int b = 0; b < 65 -buffer_i; b++)
{
if (bytes_i %2 == 0)
{
bytes.Add((byte)(buffer[b +buffer_i] << 4));
bytes_i++;
}else{
bytes[bytes_i++ /2] += buffer[b +buffer_i];
}
}
if (a +1 != input.Count)
{
if (bytes_i %2 == 0)
{
bytes.Add(0xF << 4);
bytes_i++;
}else{
bytes[bytes_i++ /2] += 0xF;
}
}
else if (bytes_i %2 != 0)
{
bytes[bytes_i++ /2] += 0xF;
}
}
return bytes;
}
解压:
public List<long> DecodeNumbers(List<byte> input)
{
List<long> numbers = new List<long>();
int buffer_i = 0;
byte[] buffer = new byte[17]; // max long = 9223372036854775807 = 160E2AD3246366807 (17 chars)
for (int a = 0; a < input.Count; a++)
{
for (int i = 0; i < 2; i++)
{
byte value = (byte)((i == 0) ? input[a] >> 4 : input[a] & 0xF);
if (value != 0xF)
{
buffer[buffer_i++] = value;
}else{
long number = 0;
for (int b = 0; b < buffer_i; b++)
{
number += buffer[buffer_i -1 -b] *(long)Math.Pow(15, b);
}
buffer_i = 0;
numbers.Add(number);
}
}
}
if (buffer_i != 0)
{
long number = 0;
for (int b = 0; b < buffer_i; b++)
{
number += buffer[buffer_i -1 -b] *(long)Math.Pow(15, b);
}
numbers.Add(number);
}
return numbers;
}
用法:
List<long> numbers = new List<long>{4,10,14,51,5990,922337203685477,64,4685746,56545674,94,1,65454677,665555,1234567890,55555,22,2,3,2,0,99999,99955500099955577,1,2,666,654154,654,58,56,69,7,55,5647,321,25,0,697,9,9,9,9,9,96,5,546,4,645545,64564564,5465498654,6476854,85849865,6478596743,6,6,1,2,3,3,3,548745,6647};
string s = "plain text:\r\n";
string str = "";
foreach (long val in numbers)
{
str += val + "|";
}
s += str + "\r\n" + str.Length + " bytes\r\n\r\n";
List<byte> encoded = EncodeNumbers(numbers);
s += "compressed base64:\r\n";
str = Convert.ToBase64String(encoded.ToArray());
s += str + "\r\n" + str.Length + " bytes\r\n\r\n";
List<long> decompressed = DecodeNumbers(encoded);
str = "";
foreach (long val in decompressed)
{
str += val + "|";
}
s += "decompressed:\r\n" + str + "\r\n" + str.Length + " bytes";
Clipboard.SetText(s);
输出:
plain text:
4|10|14|51|5990|922337203685477|64|4685746|56545674|94|1|65454677|665555|1234567890|55555|22|2|3|2|0|99999|99955500099955577|1|2|666|654154|654|58|56|69|7|55|5647|321|25|0|697|9|9|9|9|9|96|5|546|4|645545|64564564|5465498654|6476854|85849865|6478596743|6|6|1|2|3|3|3|548745|6647|
278 bytes
compressed base64:
T6/vNvG5X3GXGSLIRS9E9ihYH05uQZ9k8fWy3qL9IwX3NbfWDxFtrxfy8/L/HpafNlXR4iHg2i8fLy5vzcVPLZ89879J9/OvGhfxZvGv8xf5+fn5+fZvXyZvT8tBX1oFOU8h7FcB74fhBPeAvuXyfbdDSPb28fLz8/P6yNDx6C8=
172 bytes
decompressed:
4|10|14|51|5990|922337203685477|64|4685746|56545674|94|1|65454677|665555|1234567890|55555|22|2|3|2|0|99999|99955500099955574|1|2|666|654154|654|58|56|69|7|55|5647|321|25|0|697|9|9|9|9|9|96|5|546|4|645545|64564564|5465498654|6476854|85849865|6478596743|6|6|1|2|3|3|3|548745|6647|
278 bytes
由于数据类型转换,当数字接近 long int 的最大值时,会有一点数据丢失,这可以在 99955500099955577 与 99955500099955574 上看到。