在Java中将UUID编码为15个字符的字符串

时间:2014-12-19 19:07:23

标签: java

我在这里看到几个相似的问题,但没有一个是我需要的。由于不幸无法更改的原因,我需要使用java UUID并将其存储在15个字符长的字符串中。我发现的基本方法的所有数值变化只能将其减少到最多22个字符,但我认为应该可以使它更短。有谁知道如何做到这一点?弦越短越好。谢谢!

2 个答案:

答案 0 :(得分:1)

UUID由128位组成。这可以存储在15个字符串的java字符串中,因为java字符是16位,包含UTF-16字符。并非所有16位值都可以采用,对于更高的Unicode值,某些字符必须成对出现。但是我们每个字符只需要9比特的有效载荷(15个字符* 9比特有效载荷> = 128比特)。

因此我们可以为每个字符存储9位有效负载,例如从U + 2000开始。

public static String uuidToStr15(UUID uuid) {
    long[] longs = new long[2];
    longs[0] = uuid.getLeastSignificantBits();
    longs[1] = uuid.getMostSignificantBits();
    System.out.println("uuidToStr15: " + Arrays.toString(longs));

    char[] chars = new char[15];
    // 15 chars x 9 bits payload == 135 >=  128.
    final int bitsPerChar = (128 + chars.length - 1) / chars.length;
    final int char0 = 0x2000;
    long mask = (1L << bitsPerChar) - 1;
    for (int i = 0; i < chars.length; ++i) {
        int payload = (int)(longs[0] & mask);
        chars[i] = (char)(char0 + payload);
        longs[0] >>>= bitsPerChar;
        longs[0] |= (longs[1] & mask) << (64 - bitsPerChar);
        longs[1] >>>= bitsPerChar;
    }
    return new String(chars);
}

public static UUID str15ToUuid(String s) {
    char[] chars = s.toCharArray();
    if (chars.length != 15) {
        throw new IllegalArgumentException(
                "String should have length 15, not " + chars.length);
    }
    final int bitsPerChar = (128 + chars.length - 1) / chars.length;
    final int char0 = 0x2000;
    long mask = (1L << bitsPerChar) - 1;
    long[] longs = new long[2];
    //for (int i = 0; i < chars.length; ++i) {
    for (int i = chars.length - 1; i >= 0; --i) {
        int payload = (int) chars[i];
        if (payload < char0) {
            throw new IllegalArgumentException(
                     String.format("Char [%d] is wrong; U+%04X",
                         i, payload));
        }
        payload -= char0;
        longs[1] <<= bitsPerChar;
        longs[1] |= (longs[0] >>> (64 - bitsPerChar)) & mask;
        longs[0] <<= bitsPerChar;
        longs[0] |= payload;
    }
    System.out.println("str15ToUuid: " + Arrays.toString(longs));
    return new UUID(longs[1], longs[0]);
}

public static void main(String[] args) {
    UUID uuid = UUID.randomUUID();
    System.out.println("UUID; " + uuid.toString());
    String s = uuidToStr15(uuid);
    UUID uuid2 = str15ToUuid(s);
    System.out.println("Success: " + uuid2.equals(uuid));
}

当然这些字符串不容易写下来或键入键盘。为此,需要更加小心,并选择Unicode代码点的范围。

另外&#34; 15个字符&#34; UTF-16中只有30个字节,但UTF-8的物理尺寸更长。

答案 1 :(得分:-1)

从Java语言规范3.10.5. String Literals(注意粗体部分):

  

字符串文字由包含的零个或多个字符组成   双引号。字符可以由转义序列表示   (§3.10.6) - U + 0000到的字符的一个转义序列   U + FFFF,UTF-16代理代码单元的两个转义序列   U + 010000到U + 10FFFF范围内的字符。   有关EscapeSequence的定义,请参见§3.10.6。

     

字符串文字的类型始终为String (§4.3.3)。

Java String中的每个“字符”都可以是UTF-16值。含义长度为15的字符串最多可以为30个字节。

也许您认为在Java中,字符将映射到一个字节(一个8位值)。但事实并非如此。

因此,相反,我们会选择使用byte []数组进行编码。实际上,在现实生活中,当我们想要将事物编码为8位值(原始字节,如C,无符号字符中所理解)时,我们就会这样做。

然后,让我们做一些数学。根据定义,a UUID is a 128-bit value。 128位值是一个16字节的序列(128 = 16 * 8。)

所以,你无法将UUID普遍编码为15个字节。 UUID版本1到3可能包含可以压缩或忽略的冗余或重复值(假设读者可以正确识别这些“丢弃”值是什么。)

但是一旦你使用UUID v4和v5,就算了吧。这几乎是一系列随机值,在一般情况下几乎是不可压缩的。

基本算术然后告诉我们,我们不应该尝试这样做:)