我正在尝试将 md5 字符串(base 16)转换为 c++ 中的 base 62 字符串。到目前为止,我发现的每个转换为 base 62 的解决方案只有在您可以将您的数字表示为 64 位整数或更小的整数时才有效。一个 md5 字符串是 128 位的,我一个人对此一无所获。
我应该只包含一个 bigint 库并完成它吗?
让我们来看看。128/log2(62)=21.497。这意味着您需要 22 个“数字”来表示 base-62。
如果您只对不超过 22 个字符且不使用超过 62 个不同字符的字符串表示感兴趣,则不需要真正的 base-62 表示。您可以将 128 位分解为更小的部分并分别编码。这样您就不需要任何 128 位算术。您可以将 128 位拆分为 2x64 位,并使用长度为 11 的字符串对每个 64 位块进行编码。这样做甚至可以仅使用 57 个不同的字符。因此,您可以消除 62 个字符中的 5 个以避免任何“视觉歧义”。例如,删除 l,1,B,8。剩下 58 个不同的字符和 11*log2(58)=64.438 刚好够编码 64 位。
获得两个 64 位块并不难:
#include <climits>
#if CHAR_BIT != 8
#error "platform not supported, CHAR_BIT==8 expected"
#endif
// 'long long' is not yet part of C++
// But it's usually a supported extension
typedef unsigned long long uint64;
uint64 bits2uint64_bigendian(unsigned char const buff[]) {
return (static_cast<uint64>(buff[0]) << 56)
| (static_cast<uint64>(buff[1]) << 48)
| (static_cast<uint64>(buff[2]) << 40)
| (static_cast<uint64>(buff[3]) << 32)
| (static_cast<uint64>(buff[4]) << 24)
| (static_cast<uint64>(buff[5]) << 16)
| (static_cast<uint64>(buff[6]) << 8)
| static_cast<uint64>(buff[7]);
}
int main() {
unsigned char md5sum[16] = {...};
uint64 hi = bits2uint64_bigendian(md5sum);
uint64 lo = bits2uint64_bigendian(md5sum+8);
}
为简单起见,您可以使用我的 uint128_t c++ 类 ( http://www.codef00.com/code/uint128.h )。有了它,基本转换器看起来就像这样简单:
#include "uint128.h"
#include <iostream>
#include <algorithm>
int main() {
char a[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
uint128_t x = U128_C(0x130eb6003540debd012d96ce69453aed);
std::string r;
r.reserve(22); // shouldn't result in more than 22 chars
// 6-bits per 62-bit value means (128 / 6 == 21.3)
while(x != 0) {
r += a[(x % 62).to_integer()];
x /= 62;
}
// when converting bases by division, the digits are reversed...fix that :-)
std::reverse(r.begin(), r.end());
std::cout << r << std::endl;
}
这打印:
J7JWEJ0YbMGqaJFCGkUxZ
GMP为任意精度整数提供了方便的 c++ 绑定