我在这里看到几个相似的问题,但没有一个是我需要的。由于不幸无法更改的原因,我需要使用java UUID并将其存储在15个字符长的字符串中。我发现的基本方法的所有数值变化只能将其减少到最多22个字符,但我认为应该可以使它更短。有谁知道如何做到这一点?弦越短越好。谢谢!
答案 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,就算了吧。这几乎是一系列随机值,在一般情况下几乎是不可压缩的。
基本算术然后告诉我们,我们不应该尝试这样做:)