将字符串编码为Base36

8

目前我正在研究一种算法,将普通字符串中的每个字符编码成Base36字符串。

我尝试了以下方法,但没有成功。

public static String encode(String str) {
    return new BigInteger(str, 16).toString(36);
}

我猜是因为该字符串不仅是十六进制字符串。如果我使用“Hello22334!”这个字符串在Base36中,那么会产生NumberFormatException。
我的做法是将每个字符转换为数字。将数字转换为十六进制表示,然后将十六进制字符串转换为Base36。
我的方法可行吗?是否有更简单或更好的方法?

我不明白“每个可能的字符”和使用16进制的BigInteger如何结合在一起。你可能需要先将字符串转换为字节,然后再进行转换。请记住,字符串的字节表示取决于所使用的编码方式,如果没有提供编码方式,则会使用系统默认值(并且在不同系统上运行时可能会发生变化)。 - Thomas
我刚试了一下,但它不起作用。问题是,我不知道任何可能的解决方案。 - Patrick Vogt
2
你可以看一下 java.util.Base64 是如何实现的,然后将其适应为基于36进制的编码。 - Thomas
2个回答

15

首先,您需要将字符串转换为一组字节表示的数字。这就是您使用编码的原因。我强烈建议使用UTF-8。

然后,您需要将该数字、字节集转换为36进制的字符串。

byte[] bytes = string.getBytes(StandardCharsets.UTF_8); 
String base36 = new BigInteger(1, bytes).toString(36);

解码:

byte[] bytes = new Biginteger(base36, 36).toByteArray();
// Thanks to @Alok for pointing out the need to remove leading zeroes.
int zeroPrefixLength = zeroPrefixLength(bytes);
String string = new String(bytes, zeroPrefixLength, bytes.length-zeroPrefixLength, StandardCharsets.UTF_8));

private int zeroPrefixLength(final byte[] bytes) {
    for (int i = 0; i < bytes.length; i++) {
        if (bytes[i] != 0) {
            return i;
        }
    }
    return bytes.length;
}

虽然这里使用了 BigInteger,但我认为这是一个奇怪的开始方法。 - greybeard
1
没问题。 :) 我稍微编辑了答案。您可以将1作为BigInteger构造函数的第一个参数传递,使其始终为正数。 如果回答解决了您的问题,请标记答案为已接受。 :) - Christoffer Hammarström
@alalamin:类似于 new String(new Biginteger(base36, 36).toByteArray(), StandardCharsets.UTF_8) 这样的代码应该可以实现,但我还没有测试过。 - Christoffer Hammarström
1
解码可能不总是给出相同的结果,因为BigInteger在某些情况下会在字节数组前加上0x00。 - Alok
@Alok 谢谢,很好知道。我实际上没有测试解码。 - Christoffer Hammarström
显示剩余5条评论

3

从十进制到三十六进制

public static String toBase36(String str) {
        try {
            return Long.toString(Long.valueOf(str), 36).toUpperCase();
        } catch (NumberFormatException | NullPointerException ex) {
            ex.printStackTrace();
        }
        return null;
    }

从 Base36 字符串转换为 Base10

public static String fromBase36(String b36) {
        try {
            BigInteger base = new BigInteger( b36, 36);
            return base.toString(10);
        }catch (Exception e){
             e.printStackTrace();
        }
       return null;
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接