Я потратил некоторое время на это, и у меня есть для вас хорошее решение.
Кодируйте как base64, а затем как пользовательский base32, который использует 0-9a-v.По сути, вы размещаете биты 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");
}