如何将long转换为可打印的字节

时间:2013-12-04 20:35:56

标签: java encoding

我有一个表示长的字符串。像"12345678901"(11个字符长)。

我使用Long.parse()将其转换为long,这很好。

现在,我希望将这个长字符串作为短字符串发送,例如"eR%s"

目标是让最后一个字符串尽可能短。知道最好的方法是什么?我可以使用更多字符作为URL编码(就像我可以使用/,%,:等)

4 个答案:

答案 0 :(得分: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();
    }
}

答案 1 :(得分:0)

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

答案 2 :(得分:0)

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

Long.toString(num, 16)

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

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

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

答案 3 :(得分:0)

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

所以我构建了类似的东西(见下文),它在base92(几乎)中转换了很长的内容。它使用除了减号和管道之外的所有可打印字符,我用它来分隔符。

它几乎是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;
  }
}