我正在寻找一种方法来识别(即编码和解码)一组带有一个令牌的Java字符串。标识不应涉及DB持久性。到目前为止,我已经研究过Base64编码和DES加密,但就以下要求而言,两者都不是最优的:
Base32是我最好的选择还是有更好的选择?请注意,我主要对缩短和缩短模糊集合,加密/安全性并不重要。
答案 0 :(得分:2)
文本的结构是什么(即字符串集)?您可以使用它的知识以缩短的形式对其进行编码。例如。如果您有大的基数十进制数“1234567890”,您可以将其翻译成36个基数,这将更短。
否则看起来你正在尝试发明一个通用的归档器。
如果您不关心长度,那么是的,通过基于字母的编码器(例如Base32)进行处理是唯一的选择。
此外,如果文字足够大,也许你可以通过压缩来节省一些空间。
答案 1 :(得分:2)
Rot13会混淆,但不会缩短。 Zip缩短(通常)但不会在URL往返中存活。加密不会缩短,也可能会延长。哈希缩短但是单向。你没有一个简单的问题。 Base32不区分大小写,但比Base64占用更多空间,而不是。我怀疑你将不得不放弃或修改你的要求。哪些要求最重要哪个最不重要?
答案 2 :(得分:1)
我花了一些时间在这上面,我有一个很好的解决方案。
编码为base64,然后编码为使用0-9a-v的自定义base32。基本上,你一次布局6位(你的字符是0-9a-zA-Z),然后一次编码5。这几乎不会产生任何额外的空间。例如,ABCXYZdefxyz123789
编码为i9crnsuj9ov1h8o4433i14
这是一个有效的实现,包括一些证明它不区分大小写的测试代码:
// Note: You can add 1 more char to this if you want to
static String chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static String decodeToken(String encoded) {
// Lay out the bits 5 at a time
StringBuilder sb = new StringBuilder();
for (byte b : encoded.toLowerCase().getBytes())
sb.append(asBits(chars.indexOf(b), 5));
sb.setLength(sb.length() - (sb.length() % 6));
// Consume it 6 bits at a time
int length = sb.length();
StringBuilder result = new StringBuilder();
for (int i = 0; i < length; i += 6)
result.append(chars.charAt(Integer.parseInt(sb.substring(i, i + 6), 2)));
return result.toString();
}
private static String generateToken(String x) {
StringBuilder sb = new StringBuilder();
for (byte b : x.getBytes())
sb.append(asBits(chars.indexOf(b), 6));
// Round up to 5 bit multiple
// Consume it 5 bits at a time
int length = sb.length();
sb.append("00000".substring(0, length % 5));
StringBuilder result = new StringBuilder();
for (int i = 0; i < length; i += 5)
result.append(chars.charAt(Integer.parseInt(sb.substring(i, i + 5), 2)));
return result.toString();
}
private static String asBits(int index, int width) {
String bits = "000000" + Integer.toBinaryString(index);
return bits.substring(bits.length() - width);
}
public static void main(String[] args) {
String input = "ABCXYZdefxyz123789";
String token = generateToken(input);
System.out.println(input + " ==> " + token);
Assert.assertEquals("mixed", input, decodeToken(token));
Assert.assertEquals("lower", input, decodeToken(token.toLowerCase()));
Assert.assertEquals("upper", input, decodeToken(token.toUpperCase()));
System.out.println("pass");
}