【问题标题】:How to convert a long into printable bytes如何将 long 转换为可打印字节
【发布时间】:2013-12-04 20:35:56
【问题描述】:

我有一个代表长的字符串。喜欢"12345678901"(11 个字符长)。

我用Long.parse()把它转换成long,没关系。

现在,我想将它作为一个短字符串发送,例如通过网络发送"eR%s"。

我们的目标是使这个最终字符串尽可能短。知道什么是最好的方法吗?我可以使用更多字符作为 URL 编码(比如我可以使用 /、%、: 等)

【问题讨论】:

  • 12345678901如何转换为eR%s?
  • 另外,将其标记为“如何将 Long 转换为 byte[] 并返回 java ”的重复项的人可能没有真正阅读过这个问题,也没有真正阅读过关于“我如何转换 Long”的问题到 byte[] 并返回到 java" ;) 我不是在问如何创建一个 long to byte 数组。这很容易。我在问如何对其进行编码...下次阅读更好。
  • Base64 可能是您使用现成工具所能做的最好的事情。理论上你可以在极端情况下使用 Base95 左右,但它不会很好地通过网络传输。
  • 声称的“重复”不是。

标签: java encoding


【解决方案1】:

Java 可以使用数字 0 - 9 和小写字母 a - z 处理高达 36 的基数。

> Long.toString(12345678901L, 36)
"5o6aqt1"

> Long.parseLong("5o6aqt1", 36)
12345678901

您可以使用 66 个未保留的 URI 字符中的 65 个创建自己的编码(因此您的 URI 不需要转义)。 '-' 符号需要用于负数:

> Long65.toString(12345678901L)
"aFDIbA"

> Long65.parseLong65("aFDIbA")
12345678901

这是Long65()的代码

import java.math.BigInteger;

public class Long65 {
    private static int base = 65;
    private static String URIchars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_.~";

    public static String toString(Long aNumber) {
        StringBuilder result = new StringBuilder();
        if (aNumber < 0) {
            result.append('-');
            aNumber = -aNumber;
        }
        int r = (int)(aNumber % base);
        if (aNumber - r == 0) 
            result.append(URIchars.charAt(r));
        else 
            result.append(Long65.toString((aNumber - r) / base) + URIchars.charAt(r));
        return result.toString();
    }

    public static long parseLong65(String aNumber) {
        char[] digits;
        int sign = 1;
        if (aNumber.charAt(0) == '-') {
            sign = -1;
            digits = aNumber.substring(1).toCharArray();
        } else {
            digits = aNumber.toCharArray();
        }
        BigInteger bigBase = BigInteger.valueOf(base);
        BigInteger power = bigBase.pow(digits.length);
        BigInteger total = BigInteger.valueOf(0);
        for (char digit : digits){
            power = power.divide(bigBase);
            total = total.add(power.multiply(BigInteger.valueOf(URIchars.indexOf(digit))));
        }
        return sign * total.longValue();
    }
}

【讨论】:

  • "Long.toString(12345678901L, 36)" 很可能会满足我的要求!谢谢。我将深入研究 Long65,看看它是否比 Long.toString() 更占用内存。我需要调用这个方法发送千亿行......所以想尽可能避免GC。
  • 我对 Long65 进行了更改,因为我注意到它需要 BigInteger 才能支持 long int 的全部范围。字符串中的节省是每个数字 0 到 2 个字符。
  • Base64 是执行此操作的标准方法。
  • Base64 不是答案。这只是一个短语。请举例说明如何使用它来解决问题。 Base64 中使用的两个字符必须进行转义。 Java中有Base64编码器吗?
【解决方案2】:

如果您想要更短的表示,请为您的号码使用不同的基数。

【讨论】:

    【解决方案3】:

    您使用的数字基数越大,表示越小。例如,您可以尝试以 16 为基数:

    Long.toString(num, 16)
    

    这应该返回一个最多 16 个字符的字符串。

    如果这还不够小,您可以在更大的基础上构建表示。但是,如果需要对结果字符串进行 URL 转义,这可能没有用。例如,在 base 256 中,8 个字符对于任何数字都足够了,但是 256 个字符中的许多需要转义,从而使生成的文本更长。因此,如果您选择自己实现这样的编码/解码方案,则必须仔细选择您的字母表。

    以http://en.wikipedia.org/wiki/Base64 为例。您可以使用this Java implementation。你可能也对Base85 and its implementations感兴趣。

    【讨论】:

    • 感谢您指向 Base85... 我可能会尝试一下,看看结果是否适合我。
    【解决方案4】:

    要回复 cmets Base64 与其他选项,我会说,这完全取决于您对字符集的限制。我不是在谈论通过 URL 传输,而是通过需要是文本流的字符流。我不能简单地发送一个字节数组,因为不可打印的字符可能会导致某些问题。

    所以我构建了类似的东西(见下文),它在 base92 中转换 long(几乎)。它使用所有可打印的字符,不包括我用于分隔符的减号和管道。

    这几乎是 Base65 的一个切入点,我只是动态地构建有效数字列表。可重复用于任何基数或任何有效数字列表。

    <!-- language: java -->
    public class LongConverter {
    
      private static String URIchars;
    
      static {
        StringBuilder result = new StringBuilder();
        for (int i = 32; i < 255; i++) {
          if ((i != 45) && (i != 124))
            result.append((char)i);
        }
        URIchars = result.toString();
      }
    
    
      public static String toString(Long aNumber) {
        int base = URIchars.length();
        StringBuilder result = new StringBuilder();
        if (aNumber < 0) {
          result.append('-');
          aNumber = -aNumber;
        }
        int r = (int) (aNumber % base);
        if (aNumber - r == 0) result.append(URIchars.charAt(r));
        else result.append(Long65.toString((aNumber - r) / base) + URIchars.charAt(r));
        return result.toString();
      }
    
      public static long parseLong(String aNumber) {
        int base = URIchars.length();
        char[] digits;
        int sign = 1;
        if (aNumber.charAt(0) == '-') {
          sign = -1;
          digits = aNumber.substring(1).toCharArray();
        } else {
          digits = aNumber.toCharArray();
        }
        long total = 0;
        long power = 1;
        for (int i = 0; i < digits.length; i++)
          power *= base;
        for (char digit : digits) {
          power /= base;
          total += URIchars.indexOf(digit) * power;
        }
        return sign * total;
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-02
      • 2011-08-03
      • 2012-12-15
      • 1970-01-01
      相关资源
      最近更新 更多