ダッシュのない文字列から java.util.UUID を作成するにはどうすればよいですか?
"5231b533ba17478798a3f2df37de2aD7" => #uuid "5231b533-ba17-4787-98a3-f2df37de2aD7"
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
または、 16 進文字列の各半分をlong
整数として解析し、コンストラクターにUUID
渡します。
UUID uuid = new UUID ( long1 , long2 ) ;
UUIDは 128 ビットの値です。UUID は実際には文字と数字で構成されているのではなく、ビットで構成されています。これは、非常に大きな数を表すものと考えることができます。
これらのビットを 128 個の0
&1
文字として表示できます。
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 111111100 0101 1111111111111111111111111111111111111 -111111111111111111111111111111111111 -11
人間はビットを簡単に読み取ることができないため、便宜上、通常は 128 ビットの値を文字と数字で構成される16 進数の文字列として表します。
74d25156-60e6-444c-a177-a96e67ecfc5f
このような 16 進文字列は、UUID 自体ではなく、わかりやすい表現です。ハイフンは UUID 仕様に従って正規の書式設定として追加されますが、オプションです。
74d2515660e6444ca177a96e67ecfc5f
ちなみに、UUID 仕様では、16 進文字列を生成するときに小文字を使用する必要があり、入力として大文字を許容する必要があることが明確に述べられています。残念ながら、Apple、Microsoft などの実装を含め、多くの実装が小文字生成規則に違反しています。私のブログ投稿を参照してください。
以下は、Clojure ではなく Java を指します。
Java 7 (およびそれ以前) では、java.util.UUIDクラスを使用して、入力としてハイフンを含む 16 進文字列に基づいて UUID をインスタンス化できます。例:
java.util.UUID uuidFromHyphens = java.util.UUID.fromString("6f34f25e-0b0d-4426-8ece-a8b3f27f4b63");
System.out.println( "UUID from string with hyphens: " + uuidFromHyphens );
ただし、その UUID クラスは、ハイフンなしで 16 進文字列を入力すると失敗します。UUID 仕様では 16 進文字列表現にハイフンが必要ないため、この失敗は残念です。これは失敗します:
java.util.UUID uuidFromNoHyphens = java.util.UUID.fromString("6f34f25e0b0d44268ecea8b3f27f4b63");
1 つの回避策は、正規のハイフンを追加するように 16 進文字列をフォーマットすることです。これは、正規表現を使用して16進文字列をフォーマットする試みです。注意してください…このコードは機能しますが、私は正規表現の専門家ではありません。このコードをより堅牢にする必要があります。たとえば、文字列の長さがフォーマット前に 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 );
この代替構文\\p{XDigit}
は、次の場所の正規表現内で Posix 表記を使用すると、より読みやすくなります[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
Clojure の#uuid
タグ付きリテラルは へのパススルーjava.util.UUID/fromString
です。そして、fromString
それを「-」で区切って2つの値に変換しLong
ます。( UUIDの形式は 8-4-4-4-12 の 16 進数に標準化されていますが、「-」は実際には検証と視覚的な識別のためだけに存在します。)
簡単な解決策は、「-」を再挿入して使用すること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")))
正規表現を使わないものが必要な場合は、ByteBuffer
とを使用できますDatatypeConverter
。
(defn uuid-from-string [data]
(let [buffer (java.nio.ByteBuffer/wrap
(javax.xml.bind.DatatypeConverter/parseHexBinary data))]
(java.util.UUID. (.getLong buffer) (.getLong buffer))))
正規表現ソリューションはおそらく高速ですが、それを見ることもできます:)
String withoutDashes = "44e128a5-ac7a-4c9a-be4c-224b6bf81b20".replaceAll("-", "");
BigInteger bi1 = new BigInteger(withoutDashes.substring(0, 16), 16);
BigInteger bi2 = new BigInteger(withoutDashes.substring(16, 32), 16);
UUID uuid = new UUID(bi1.longValue(), bi2.longValue());
String withDashes = uuid.toString();
ちなみにバイナリ16バイトからuuidへの変換は
InputStream is = ..binarty input..;
byte[] bytes = IOUtils.toByteArray(is);
ByteBuffer bb = ByteBuffer.wrap(bytes);
UUID uuidWithDashesObj = new UUID(bb.getLong(), bb.getLong());
String uuidWithDashes = uuidWithDashesObj.toString();
間抜けな正規表現の置換を行うことができます:
String digits = "5231b533ba17478798a3f2df37de2aD7";
String uuid = digits.replaceAll(
"(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})",
"$1-$2-$3-$4-$5");
System.out.println(uuid); // => 5231b533-ba17-4787-98a3-f2df37de2aD7
正規表現と文字列操作を使用するよりもはるかに (~ 900%) 高速なソリューションは、16 進文字列を 2 つの long に解析し、それらから UUID インスタンスを作成することです。
(defn uuid-from-string
"Converts a 32digit hex string into java.util.UUID"
[hex]
(java.util.UUID.
(Long/parseUnsignedLong (subs hex 0 16) 16)
(Long/parseUnsignedLong (subs hex 16) 16)))
public static String addUUIDDashes(String idNoDashes) {
StringBuffer idBuff = new StringBuffer(idNoDashes);
idBuff.insert(20, '-');
idBuff.insert(16, '-');
idBuff.insert(12, '-');
idBuff.insert(8, '-');
return idBuff.toString();
}
他の誰かがこのアプローチの計算効率についてコメントできるかもしれません。(私のアプリケーションでは問題ありませんでした。)