我需要用最短的字符串表示非常大和小的数字。这些数字是未签名的。我已经尝试过直接的Base64编码,但是对于一些较小的数字,编码的字符串比仅将数字存储为字符串更长。在URL最安全的情况下,以最短的字符串最佳地存储非常大或短的数字的最佳方法是什么?
答案 0 :(得分:3)
我尝试过直接的Base64编码,但是对于一些较小的数字,编码的字符串比将数字存储为字符串更长
二进制字节数据的Base64编码将使其更长,大约三分之一。它不应该缩短,而是允许以非二进制安全的格式安全传输二进制数据。
然而,基数64比数字(或字节数据)的十进制表示更紧凑,即使它比基数256(原始字节数据)更紧凑。直接在base 64中编码你的数字将使它们比十进制更紧凑。这样就可以了:
private static final String base64Chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
static String encodeNumber(long x) {
char[] buf = new char[11];
int p = buf.length;
do {
buf[--p] = base64Chars.charAt((int)(x % 64));
x /= 64;
} while (x != 0);
return new String(buf, p, buf.length - p);
}
static long decodeNumber(String s) {
long x = 0;
for (char c : s.toCharArray()) {
int charValue = base64Chars.indexOf(c);
if (charValue == -1) throw new NumberFormatException(s);
x *= 64;
x += charValue;
}
return x;
}
使用此编码方案,Long.MAX_VALUE
将是字符串H__________
,长度为11个字符,与其长度为19个字符的十进制表示9223372036854775807
进行比较。最多约1600万的数字仅适合4个字符。那差不多就像你得到它一样短。 (从技术上讲,还有另外两个不需要在URL中编码的字符:.
and ~
。你可以将它们合并到基数66,对于某些数字来说这可能是一个较短的smidgin,尽管这看起来有点迂腐。)
答案 1 :(得分:1)
假设您没有进行任何压缩,并且您将自己限制为URL安全字符,那么以下过程将为您提供最紧凑的编码。
那么,压缩呢......
如果您假设您所代表的数字在其范围内均匀分布,那么就没有真正的压缩机会。
否则, potential 用于压缩。如果您可以减小公共数字的大小,那么通常可以通过压缩实现节省。这就是霍夫曼编码的工作原理。
但缺点是在这个级别的压缩在数字范围内并不完美。它减少了一些数字的大小,但它不可避免地增加了其他数字的大小。
那么这对您的用例意味着什么?
我认为这意味着你正在以错误的方式看问题。您不应该针对每个数字的最小编码大小。您的目标应该是平均最小化...平均数量的实际分布。
答案 2 :(得分:1)
为了扩展Stephen C的答案,这里有一段代码转换为base 62(但你可以通过在digits
字符串中添加更多字符来增加这一点(只需选择哪些字符有效对你而言):
public static String toString(long n) {
String digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
int base = digits.length();
String s = "";
while (n > 0) {
long d = n % base;
s = digits.charAt(d) + s;
n = n / base;
}
return s;
}
这永远不会导致字符串表示长于数字。