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

在Java中将UUID编码为15个字符的字符串,java,Java,我在这里看到了几个类似的问题,但没有一个是我所需要的。不幸的是,由于无法更改的原因,我需要获取一个java UUID并将其存储在一个15个字符长的字符串中。我所发现的所有基本方法的数值变化只能将其减少到最多22个字符,但我认为应该可以将其缩短。有人知道怎么做吗?绳子越短越好。谢谢 来自Java语言规范(注意粗体部分): 字符串文字由零个或多个包含在 双引号。字符可以用转义序列表示 (§3.10.6)-一个转义序列,用于U+0000到0000范围内的字符 U+FFFF,UTF-16代理代码单元的两

我在这里看到了几个类似的问题,但没有一个是我所需要的。不幸的是,由于无法更改的原因,我需要获取一个java UUID并将其存储在一个15个字符长的字符串中。我所发现的所有基本方法的数值变化只能将其减少到最多22个字符,但我认为应该可以将其缩短。有人知道怎么做吗?绳子越短越好。谢谢

来自Java语言规范(注意粗体部分):

字符串文字由零个或多个包含在 双引号。字符可以用转义序列表示 (§3.10.6)-一个转义序列,用于U+0000到0000范围内的字符 U+FFFF,UTF-16代理代码单元的两个转义序列 范围在U+010000到U+10FFFF之间的字符。 逃逸序列的定义见§3.10.6

字符串文字总是字符串类型(§4.3.3)

Java字符串中的每个“字符”都可以是UTF-16值。这意味着长度为15的字符串最多可以是30个字节

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

因此,我们可以选择使用byte[]数组进行编码。事实上,在现实生活中,当我们想要将事物编码成8位值(如C的无符号字符中所理解的基本字节)时,我们就是这么做的

但是,让我们做一些数学。根据定义。128位值是16字节的序列(
128=16*8

所以,你根本不可能把UUID编码成15个字节。UUID版本1到3可能包含可压缩或忽略的冗余或重复值(假设读者能够正确识别那些“删除”的值)

但一旦您使用UUIDV4和v5,就忘了它。这些基本上是一系列随机值,在一般情况下非常不可压缩


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

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));
}
公共静态字符串uuidToStr15(UUID UUID){
长[]长=新长[2];
longs[0]=uuid.getLeastSignificantBits();
longs[1]=uuid.getMostSignificantBits();
System.out.println(“uuidToStr15:+Arrays.toString(longs));
char[]chars=新字符[15];
//15个字符x 9位有效负载==135>=128。
final int-bitsPerChar=(128+chars.length-1)/chars.length;
最终int char0=0x2000;
长掩码=(1L>>=bitsPerChar;
longs[0]|=(longs[1]&掩码)>>=bitsPerChar;
}
返回新字符串(字符);
}
公共静态UUID str15touid(字符串s){
char[]chars=s.toCharArray();
如果(字符长度!=15){
抛出新的IllegalArgumentException(
“字符串长度应为15,而不是”+字符长度);
}
final int-bitsPerChar=(128+chars.length-1)/chars.length;
最终int char0=0x2000;
长掩码=(1L=0;--i){
int有效载荷=(int)字符[i];
如果(有效载荷<0){
抛出新的IllegalArgumentException(
String.format(“字符[%d]错误;U+%04X”,
i、 有效载荷);
}
有效载荷-=char0;
longs[1]>(64位sperchar))&掩码;

longs[0]Java UUID是128位。在base64中,这是128/6=21.3个可打印字符(这就是22的来源)。即使考虑到8位字符(其中许多字符依赖于编码或不可打印),这仍然是16个字符。对于128位,可能8个
char
s是最小值,但这些不一定表示有效的
String
s。因此,您可能需要更多的字符。@njzk2您是对的,只是一个小的加法-您可以使用utf-16来表示8个字符的字符串,但在字节中,它仍然是16bytes@Lashane:并非所有16个字节都可以使用,因为并非所有组合都是有效的utf-16字符。(因为代理项对)除非位模式高度重复或先验已知,否则我们无法在8字节上编码128个均匀分布的位。请参阅我的答案:)UTF-16是每个字符2字节。一些数学表明128/16=8个字符串。OP的问题中提到他想要15个字节吗?他想要15个字符的字符串。如果我的代码是8个字符字符,加上7个填充字符和中提琴。您没有正确回答他的问题,因为128位可以容纳8个UTF-16字符。@mbomb007-128位值*为此目的精心选择的值可以容纳8个UTF-16字符。很明显,这是正确的。但是,在一般情况下,您不能(这是一个包含随机字符的真实UUID会发生的情况,而不仅仅是“8”个字符)。@realpoint-阅读理解。通过他的问题,很明显他试图将一个Java UUID操纵成一个15个字符的Java字符串(根据定义是UTF-16编码的)。你根本不能(即使他可以也不应该)使用15个字节将问题(将UUID存储为15个UTF-16字符)简化为一个更简单的模型有助于了解为什么这是不可能的。