【问题标题】:Encode String to Base36将字符串编码为 Base36
【发布时间】:2017-05-28 18:41:35
【问题描述】:

目前我正在研究一种算法,将带有每个可能字符的普通字符串编码为 Base36 字符串。

我尝试了以下方法,但它不起作用。

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

我猜这是因为字符串不仅仅是一个十六进制字符串。如果我使用字符串“Hello22334!”在 Base36 中,我得到一个 NumberFormatException

我的方法是将每个字符转换为数字。将数字转换为十六进制表示,然后将十六进制字符串转换为 Base36。

我的方法可以吗,还是有更简单或更好的方法?

【问题讨论】:

  • 我不明白“每个可能的字符”和使用基数为 16 的 BigInteger 应该如何组合在一起。您可能希望先将字符串转换为字节并进行转换。请记住,字符串的字节表示取决于所使用的编码,如果您不提供编码,则将使用系统默认值(并且在不同系统上运行时可能会改变)。
  • 我刚试了一下,还是不行。问题是,我知道没有可能的解决方案。
  • 您可以看看java.util.Base64 是如何实现的,并将其调整为base 36。

标签: java string algorithm biginteger base36


【解决方案1】:

首先,您需要将字符串转换为数字,由一组字节表示。这就是您使用编码的目的。我强烈推荐 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 可以解决这个问题,但我认为这是一种奇怪的方法。
  • 没问题。 :) 我确实稍微编辑了答案。您可以将 1 作为第一个参数传递给 BigInteger 构造函数,使其始终为正数。如果回答了您的问题,请将答案标记为已接受。 :)
  • @alalamin:new String(new Biginteger(base36, 36).toByteArray(), StandardCharsets.UTF_8) 之类的东西应该可以,但我还没有测试过。
  • @ChristofferHammarström 非常感谢。效果很好。
  • 解码可能并不总是给您相同的结果,因为在某些情况下,BigInteger 会在字节数组前加上 0x00。
【解决方案2】:

从 Base10 到 Base36

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

从 Base36String 到 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;
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-09-04
    • 2016-10-12
    • 1970-01-01
    • 1970-01-01
    • 2011-03-14
    • 1970-01-01
    • 2020-05-22
    相关资源
    最近更新 更多