Подтвердить что ты не робот

Создание UUID из строки без тире

Как создать java.util.UUID из строки без тире?

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

Ответ 1

Clojure #uuid tagged literal - это переход к java.util.UUID/fromString. И fromString разбивает его на "-" и преобразует его в два значения Long. (Формат UUID стандартизирован в 8-4-4-4-12 шестнадцатеричных разрядов, но "-" действительно существуют только для проверки и визуальная идентификация.)

Прямое решение состоит в том, чтобы повторно вставить "-" и использовать 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))))

Ответ 2

TL;DR

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

Биты, а не текст

A UUID - это 128-битное значение. UUID фактически не состоит из букв и цифр, он состоит из бит. Вы можете думать об этом как о очень и очень большом количестве.

Мы могли бы отображать эти биты как сто двадцать восемь символов 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 1100 1111 1100 0101 1111

Люди не легко читают биты, поэтому для удобства мы обычно представляем 128-битное значение как строку hexadecimal, состоящую из букв и цифры.

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

Такая шестнадцатеричная строка - это не UUID, а только удобное для человека представление. Дефис добавляется в спецификацию UUID как каноническое форматирование, но необязательно.

74d2515660e6444ca177a96e67ecfc5f

Кстати, спецификация UUID четко заявляет, что при генерации шестнадцатеричной строки следует использовать строчные буквы, а в верхнем регистре следует допускать входные данные. См. мой пост в блоге.


Ниже перечислены 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");

Regex

Одним из способов является форматирование шестнадцатеричной строки для добавления канонических дефис. Здесь моя попытка использовать регулярное выражение для форматирования шестнадцатеричной строки. Опасайтесь... Этот код работает, но я не эксперт по регулярному выражению. Вы должны сделать этот код более надежным, скажем, проверяя, что длина строки составляет 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 в регулярном выражении, где \\p{XDigit} заменяется на [0-9a-fA-F] (см. Pattern doc):

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

Ответ 3

Вы можете выполнить замену регулярных выражений:

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

Ответ 4

Решение Regexp, вероятно, быстрее, но вы также можете посмотреть на это:)

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();

Ответ 5

Многое (~ 900%) быстрее по сравнению с использованием регулярных выражений и манипуляций с строками - это просто проанализировать шестнадцатеричную строку на две длинные строки и создать экземпляр 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)))

Ответ 6

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();
}

Возможно, кто-то еще может прокомментировать вычислительную эффективность этого подхода. (Это не было проблемой для моего приложения.)

Ответ 7

Другое решение было бы похоже на решение Pawel, но без создания новых Strings и только для решения проблемы. Если производительность является проблемой, избегайте regex/split/replaceAll и UUID.fromString, как чума.

String hyphenlessUuid = in.nextString();
BigInteger bigInteger = new BigInteger(hyphenlessUuid, 16);
 new UUID(bigInteger.shiftRight(64).longValue(), bigInteger.longValue());

Ответ 8

Оптимизированная версия @maerics:

    String[] digitsList= {
            "daa70a7ffa904841bf9a81a67bdfdb45",
            "529737c950e6428f80c0bac104668b54",
            "5673c26e2e8f4c129906c74ec634b807",
            "dd5a5ee3a3c44e4fb53d2e947eceeda5",
            "faacc25d264d4e9498ade7a994dc612e",
            "9a1d322dc70349c996dc1d5b76b44a0a",
            "5fcfa683af5148a99c1bd900f57ea69c",
            "fd9eae8272394dfd8fd42d2bc2933579",
            "4b14d571dd4a4c9690796da318fc0c3a",
            "d0c88286f24147f4a5d38e6198ee2d18"
    };

    //Use compiled pattern to improve performance of bulk operations
    Pattern pattern = Pattern.compile("(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})");

    for (int i = 0; i < digitsList.length; i++)
    {
        String uuid = pattern.matcher(digitsList[i]).replaceAll("$1-$2-$3-$4-$5");
        System.out.println(uuid);
    }

Ответ 9

Я считаю, что следующее является самым быстрым с точки зрения производительности. Это даже немного быстрее, чем Long.parseUnsignedLong version. Это слегка измененный код, который исходит из java-uuid-generator.

 public static UUID from32(
        String id) {
    if (id == null) {
        throw new NullPointerException();
    }
    if (id.length() != 32) {
        throw new NumberFormatException("UUID has to be 32 char with no hyphens");
    }

    long lo, hi;
    lo = hi = 0;

    for (int i = 0, j = 0; i < 32; ++j) {
        int curr;
        char c = id.charAt(i);

        if (c >= '0' && c <= '9') {
            curr = (c - '0');
        }
        else if (c >= 'a' && c <= 'f') {
            curr = (c - 'a' + 10);
        }
        else if (c >= 'A' && c <= 'F') {
            curr = (c - 'A' + 10);
        }
        else {
            throw new NumberFormatException(
                    "Non-hex character at #" + i + ": '" + c + "' (value 0x" + Integer.toHexString(c) + ")");
        }
        curr = (curr << 4);

        c = id.charAt(++i);

        if (c >= '0' && c <= '9') {
            curr |= (c - '0');
        }
        else if (c >= 'a' && c <= 'f') {
            curr |= (c - 'a' + 10);
        }
        else if (c >= 'A' && c <= 'F') {
            curr |= (c - 'A' + 10);
        }
        else {
            throw new NumberFormatException(
                    "Non-hex character at #" + i + ": '" + c + "' (value 0x" + Integer.toHexString(c) + ")");
        }
        if (j < 8) {
            hi = (hi << 8) | curr;
        }
        else {
            lo = (lo << 8) | curr;
        }
        ++i;
    }
    return new UUID(hi, lo);
}

Ответ 10

Возможно, это:

String digits = "5231b533ba17478798a3f2df37de2aD7";                     
String.format("%s%s%s%s%s%s%s%s-%s%s%s%s-%s%s%s%s-%s%s%s%s-%s%s%s%s%s%s%s%s%s%s%s%s", digits.split(""));