从不带短划线的字符串创建 UUIDtl;博士位,而不是文本正则表达式

2022-08-31 16:04:36

如何从没有破折号的字符串创建java.util.UUID?

"5231b533ba17478798a3f2df37de2aD7" => #uuid "5231b533-ba17-4787-98a3-f2df37de2aD7"

答案 1

tl;博士

java.util.UUID.fromString(
    "5231b533ba17478798a3f2df37de2aD7"
    .replaceFirst( 
        "(\\p{XDigit}{8})(\\p{XDigit}{4})(\\p{XDigit}{4})(\\p{XDigit}{4})(\\p{XDigit}+)", "$1-$2-$3-$4-$5" 
    )
).toString()

5231b533-ba17-4787-98a3-f2df37de2ad7

或者将十六进制字符串的每一半解析为整数,并传递给 UUID 的构造函数long

UUID uuid = new UUID ( long1 , long2 ) ; 

位,而不是文本

UUID 是一个 128 位值。UUID实际上不是由字母和数字组成的,而是由位组成的。你可以把它想象成描述一个非常非常大的数字。

我们可以将这些位显示为一百二十八个字符。01

0111 0100 1101 0010 0101 0001 0101 0110 0110 0000 1110 0110 0100 0100 0100 1100 1010 0001 0111 0111 1010 1001 0110 1110 0110 0111 1110 1100 1111 1100 0101 1111

人类不容易读取位,因此为了方便起见,我们通常将128位值表示为由字母和数字组成的十六进制字符串。

74d25156-60e6-444c-a177-a96e67ecfc5f

这样的十六进制字符串不是UUID本身,只是一个人类友好的表示。连字符根据 UUID 规范添加为规范格式,但可选。

74d2515660e6444ca177a96e67ecfc5f

顺便说一句,UUID规范明确指出,在生成十六进制字符串时必须使用小写字母,而大写字母应允许作为输入。不幸的是,许多实现都违反了小写生成规则,包括来自Apple,Microsoft和其他公司的实现。请参阅我的博客文章


下面指的是Java,而不是Clojure。

在 Java 7(及更早版本)中,您可以使用 java.util.UUID 类基于十六进制字符串实例化 UUID,并使用连字符作为输入。例:

java.util.UUID uuidFromHyphens = java.util.UUID.fromString("6f34f25e-0b0d-4426-8ece-a8b3f27f4b63");
System.out.println( "UUID from string with hyphens: " + uuidFromHyphens );

但是,该 UUID 类在输入不带连字符的十六进制字符串时失败。此失败是不幸的,因为 UUID 规范不需要十六进制字符串表示形式的连字符。此操作将失败:

java.util.UUID uuidFromNoHyphens = java.util.UUID.fromString("6f34f25e0b0d44268ecea8b3f27f4b63");

正则表达式

一种解决方法是设置十六进制字符串的格式以添加规范连字符。这是我使用正则表达式格式化十六进制字符串的尝试。小心。。。此代码有效,但我不是正则表达式专家。您应该使此代码更加可靠,例如检查字符串的长度在格式化之前为32个字符,在格式化后为36个字符。

    // -----|  With Hyphens  |----------------------
java.util.UUID uuidFromHyphens = java.util.UUID.fromString( "6f34f25e-0b0d-4426-8ece-a8b3f27f4b63" );
System.out.println( "UUID from string with hyphens: " + uuidFromHyphens );
System.out.println();

// -----|  Without Hyphens  |----------------------
String hexStringWithoutHyphens = "6f34f25e0b0d44268ecea8b3f27f4b63";
// Use regex to format the hex string by inserting hyphens in the canonical format: 8-4-4-4-12
String hexStringWithInsertedHyphens =  hexStringWithoutHyphens.replaceFirst( "([0-9a-fA-F]{8})([0-9a-fA-F]{4})([0-9a-fA-F]{4})([0-9a-fA-F]{4})([0-9a-fA-F]+)", "$1-$2-$3-$4-$5" );
System.out.println( "hexStringWithInsertedHyphens: " + hexStringWithInsertedHyphens );
java.util.UUID myUuid = java.util.UUID.fromString( hexStringWithInsertedHyphens );
System.out.println( "myUuid: " + myUuid );

Posix 表示法

您可能会发现此替代语法更具可读性,在正则表达式中使用 Posix 表示法代替 (请参阅 Pattern 文档):\\p{XDigit}[0-9a-fA-F]

String hexStringWithInsertedHyphens =  hexStringWithoutHyphens.replaceFirst( "(\\p{XDigit}{8})(\\p{XDigit}{4})(\\p{XDigit}{4})(\\p{XDigit}{4})(\\p{XDigit}+)", "$1-$2-$3-$4-$5" );

完整示例。

java.util.UUID uuid =
        java.util.UUID.fromString (
                "5231b533ba17478798a3f2df37de2aD7"
                        .replaceFirst (
                                "(\\p{XDigit}{8})(\\p{XDigit}{4})(\\p{XDigit}{4})(\\p{XDigit}{4})(\\p{XDigit}+)",
                                "$1-$2-$3-$4-$5"
                        )
        );

System.out.println ( "uuid.toString(): " + uuid );

uuid.toString(): 5231b533-ba17-4787-98a3-f2df37de2ad7


答案 2

Clojure的标记文字java.util.UUID/fromString的传递。并且,将其拆分为“-”并将其转换为两个值。(UUID 的格式标准化为 8-4-4-4-12 个十六进制数字,但“-”实际上仅用于验证和视觉识别。#uuidfromStringLong

直接的解决方案是重新插入“-”并使用java.util.UUID/fromString

(defn uuid-from-string [data]
  (java.util.UUID/fromString
   (clojure.string/replace data
                           #"(\w{8})(\w{4})(\w{4})(\w{4})(\w{12})"
                           "$1-$2-$3-$4-$5")))

如果你想要一些没有正则表达式的东西,你可以使用ByteBufferDatatypeConverter

(defn uuid-from-string [data]
  (let [buffer (java.nio.ByteBuffer/wrap 
                 (javax.xml.bind.DatatypeConverter/parseHexBinary data))]
    (java.util.UUID. (.getLong buffer) (.getLong buffer))))