Поиск UUID в тексте с помощью регулярных выражений

224

Я ищу UUID в блоках текста с помощью регулярных выражений. В настоящее время я полагаюсь на предположение, что все UUID будут следовать шаблонам из 8-4-4-4-12 шестнадцатеричных цифр.

Кто-нибудь может вспомнить случай использования, когда это предположение было бы неверным и заставило бы меня пропустить некоторые UUID?

парень
источник
Этот вопрос от 6 лет назад должен был помочь мне с проектом найти кредитные карты в блоке текста. Впоследствии я открыл исходный код, связанный с моим постом в блоге, в котором объясняется нюанс, который вызывали UUID при поиске кредитных карт guyellisrocks.com/2013/11/…
Парень
4
Поиск соответствия шаблону регулярного выражения UUID привел меня к этому сообщению о переполнении стека, но принятый ответ на самом деле не является ответом. Кроме того, ссылка, которую вы указали в комментарии под вашим вопросом, также не имеет шаблона (если я что-то упустил). Является ли один из этих ответов чем-то, что вы в конечном итоге использовали?
ТАСС
Если вы следуете за ссылками кролика, начиная с той, которую я разместил, вы можете наткнуться на эту строку в GitHub, где есть регулярное выражение, которое я наконец-то использовал. (Понятно, что его трудно найти.) Этот код и этот файл могут вам помочь: github.com/guyellis/CreditCard/blob/master/Company.CreditCard/…
Парень,
1
Кажется, что ни один из этих ответов не дает единого регулярного выражения для всех вариантов только действительных UUID RFC 4122. Но похоже, что такой ответ был дан здесь: stackoverflow.com/a/13653180/421049
Гаррет Уилсон

Ответы:

41

Я согласен, что по определению ваше регулярное выражение не пропускает ни одного UUID. Однако может быть полезно отметить, что если вы ищете специально для глобальных уникальных идентификаторов (GUID) от Microsoft, есть пять эквивалентных строковых представлений для GUID:

"ca761232ed4211cebacd00aa0057b223" 

"CA761232-ED42-11CE-BACD-00AA0057B223" 

"{CA761232-ED42-11CE-BACD-00AA0057B223}" 

"(CA761232-ED42-11CE-BACD-00AA0057B223)" 

"{0xCA761232, 0xED42, 0x11CE, {0xBA, 0xCD, 0x00, 0xAA, 0x00, 0x57, 0xB2, 0x23}}" 
Панос
источник
3
В каких ситуациях будет найден первый шаблон? т.е. есть ли .Net-функция, которая удаляет дефисы или возвращает GUID без дефисов?
Парень
1
Вы можете получить это с myGuid.ToString ("N").
Panos
462

Регулярное выражение для uuid:

\b[0-9a-f]{8}\b-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-\b[0-9a-f]{12}\b
Ивелин
источник
19
сделать это [a-f0-9]! Как это шестнадцатеричное! Ваше регулярное выражение (как оно есть) может возвращать ложные срабатывания.
exhuma
13
В некоторых случаях вы можете даже сделать это [a-fA-F0-9] или [A-F0-9].
Ганс-Петер Стёрр
22
@ cyber-monk: [0-9a-f] идентичен [a-f0-9] и [0123456789abcdef] по значению и по скорости, поскольку регулярное выражение в любом случае превращается в конечный автомат, причем каждая шестнадцатеричная цифра превращается в запись в таблице состояний. Для точки входа в , как это работает, см en.wikipedia.org/wiki/Nondeterministic_finite_automaton
JesperSM
10
Это решение не совсем правильное. Это соответствует идентификаторам, которые имеют недопустимую версию и символы варианта согласно RFC4122. Решение @Gajus является более правильным в этом отношении. Кроме того, RFC допускает ввод символов в верхнем регистре, поэтому было бы целесообразно добавить [AF].
Брооф
4
@broofa, я вижу, что вы действительно настроены на всех, которые соответствуют только UUID, которые соответствуют RFC. Однако я думаю, что тот факт, что вам приходилось указывать на это много раз, является надежным показателем того, что не все UUID будут использовать индикаторы версии и варианта RFC. Определение UUID en.wikipedia.org/wiki/Uuid#Definition устанавливает простой шаблон 8-4-4-4-12 и 2 ^ 128 возможностей. RFC представляет только подмножество этого. Итак, что вы хотите соответствовать? Подмножество или все они?
Бруно Броноски
120

@ivelin: UUID может иметь заглавные буквы. Так что вам нужно либо toLowerCase () строки, либо использовать:

[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}

Только что прокомментировал это, но не достаточно репутации :)

Мэтью Ф. Роббен
источник
22
Обычно вы можете справиться с этим, определив шаблон как нечувствительный к регистру с i после шаблона, что делает шаблон более чистым: / [0-9a-f] {8} - [0-9a-f] {4} - [0 -9a-f] {4} - [0-9a-f] {4} - [0-9a-f] {12} / i
Томас Биндзус,
@ThomasBindzus Эта опция доступна не на всех языках. Оригинальный шаблон в этом ответе работал для меня в Go. /.../iВерсия не сделал.
Крис Редфорд
110

UUID версии 4 имеют форму xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx, где x - любая шестнадцатеричная цифра, а y - одно из 8, 9, A или B. Например, f47ac10b-58cc-4372-a567-0e02b2c3d479.

источник: http://en.wikipedia.org/wiki/Uuid#Definition

Следовательно, это технически более правильно:

/[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89aAbB][a-f0-9]{3}-[a-f0-9]{12}/
Gajus
источник
Я не думаю, что вы имеете в виду az.
Бруно Броноски
8
Нужно принять [AF] тоже. Согласно разделу 3 RFC4122: «Шестнадцатеричные значения от« a »до« f »выводятся как символы нижнего регистра и нечувствительны к регистру при вводе ». Также (:?8|9|A|B), вероятно, немного более читабельным, как[89aAbB]
брофа
1
Необходимо скопировать модификацию @ broofa; так как ваш исключает строчные буквы A или B.
ELLIOTTCABLE
6
@elliottcable В зависимости от вашей среды, просто используйте i(без учета регистра) флаг.
Гаюс
20
Вы отказываетесь от версий 1 до 3 и 5. Почему?
iGEL
90

Если вы хотите проверить или проверить конкретную версию UUID , вот соответствующие регулярные выражения.

Обратите внимание, что единственным отличием является номер версии , который объясняется в 4.1.3. Versionглаве UUID 4122 RFC .

Номер версии является первым символом третьей группы [VERSION_NUMBER][0-9A-F]{3}:

  • UUID v1:

    /^[0-9A-F]{8}-[0-9A-F]{4}-[1][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i
  • UUID v2:

    /^[0-9A-F]{8}-[0-9A-F]{4}-[2][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i
  • UUID v3:

    /^[0-9A-F]{8}-[0-9A-F]{4}-[3][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i
  • UUID v4:

    /^[0-9A-F]{8}-[0-9A-F]{4}-[4][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i
  • UUID v5:

    /^[0-9A-F]{8}-[0-9A-F]{4}-[5][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i
Иван Габриэле
источник
Шаблоны не включают строчные буквы. Он также должен содержать a-fрядом с каждой A-Fобластью действия.
Павел Пштич
27
Символ iв конце регулярного выражения помечает его как нечувствительный к регистру.
johnhaley81
Модификатор шаблона не всегда может быть использован. Например, в определении openapi шаблон чувствителен к регистру
Stephane Janicaud
1
@StephaneJanicaud В OpenAPI вы должны использовать formatмодификатор, установив его в «uuid» вместо использования регулярного выражения для тестирования UUID: swagger.io/docs/specification/data-models/data-types/#format
Иван Габриэле
Спасибо @IvanGabriele за подсказку, это был просто пример, это та же проблема, когда вы не хотите проверять любой регистр без учета регистра.
Стефан Янико
35
/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89AB][0-9a-f]{3}-[0-9a-f]{12}$/i

Регулярное выражение Gajus отклоняет UUID V1-3 и 5, даже если они действительны.

Игель
источник
1
Но он допускает недопустимые версии (например, 8 или A) и недопустимые варианты.
Брайс
Обратите внимание, что AB в [89AB] [0-9a-f] - верхний регистр, а остальные разрешенные символы - строчные. Это поймало меня в Python
Тони Сепия
17

[\w]{8}(-[\w]{4}){3}-[\w]{12} работал для меня в большинстве случаев.

Или если вы хотите быть действительно конкретным [\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12}.

скудный
источник
3
Стоит отметить, что \ w, по крайней мере в Java, соответствует _, а также шестнадцатеричным цифрам. Замена \ w на \ p {XDigit} может быть более подходящей, поскольку это класс POSIX, определенный для сопоставления шестнадцатеричных цифр. Это может сломаться при использовании других кодировок Unicode, хотя.
oconnor0
1
@oconnor \wобычно означает «символы слова». Это будет намного больше, чем шестнадцатеричные цифры. Ваше решение намного лучше. Или, для совместимости / читабельности вы можете использовать[a-f0-9]
exhuma
1
Вот строка, которая выглядит как регулярное выражение и соответствует этим шаблонам, но является недопустимым регулярным выражением: 2wtu37k5-q174-4418-2cu2-276e4j82sv19
Трэвис Стивенс
@OleTraveler не соответствует действительности, работает как шарм. import re def valid_uuid(uuid): regex = re.compile('[\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12}', re.I) match = regex.match(uuid) return bool(match) valid_uuid('2wtu37k5-q174-4418-2cu2-276e4j82sv19')
Томаш Войчик
3
@tom Эта строка (2wt ...) является недопустимым UUID, но шаблон, приведенный в этом ответе, соответствует этой строке, неверно указывая, что это действительный UUID. Жаль, я не помню, почему этот UUID недействителен.
Трэвис Стивенс
10

В python re, вы можете перейти от цифр до букв верхнего регистра. Так..

import re
test = "01234ABCDEFGHIJKabcdefghijk01234abcdefghijkABCDEFGHIJK"
re.compile(r'[0-f]+').findall(test) # Bad: matches all uppercase alpha chars
## ['01234ABCDEFGHIJKabcdef', '01234abcdef', 'ABCDEFGHIJK']
re.compile(r'[0-F]+').findall(test) # Partial: does not match lowercase hex chars
## ['01234ABCDEF', '01234', 'ABCDEF']
re.compile(r'[0-F]+', re.I).findall(test) # Good
## ['01234ABCDEF', 'abcdef', '01234abcdef', 'ABCDEF']
re.compile(r'[0-f]+', re.I).findall(test) # Good
## ['01234ABCDEF', 'abcdef', '01234abcdef', 'ABCDEF']
re.compile(r'[0-Fa-f]+').findall(test) # Good (with uppercase-only magic)
## ['01234ABCDEF', 'abcdef', '01234abcdef', 'ABCDEF']
re.compile(r'[0-9a-fA-F]+').findall(test) # Good (with no magic)
## ['01234ABCDEF', 'abcdef', '01234abcdef', 'ABCDEF']

Это делает простейшее регулярное выражение Python UUID:

re_uuid = re.compile("[0-F]{8}-([0-F]{4}-){3}[0-F]{12}", re.I)

Я оставлю это в качестве упражнения для читателя, чтобы использовать timeit для сравнения их производительности.

Наслаждаться. Держите это Pythonic ™!

ПРИМЕЧАНИЕ. Эти промежутки также будут совпадать, :;<=>?@'поэтому, если вы подозреваете, что это может дать вам ложные срабатывания, не используйте ярлык. (Спасибо, Оливер Обер, за то, что указал на это в комментариях.)

Бруно Броноски
источник
2
[0-F] будет действительно соответствовать 0-9 и AF, но также любому символу, чей код ASCII находится между 57 (для 9) и 65 (для A), то есть любой из:; <=>? @ '.
Оливье Обер
7
Так что не используйте вышеупомянутый код, за исключением случаев, когда вы хотите рассмотреть: =>;? <;: - <@ =: - @ =; = - @; @: -> == @?> =:? = @; как действительный UUID :-)
Оливье Обер
9

По определению UUID - это 32 шестнадцатеричные цифры, разделенные на 5 групп дефисами, как вы уже описали. Вы не должны пропустить ни одного со своим регулярным выражением лица.

http://en.wikipedia.org/wiki/Uuid#Definition

pix0r
источник
2
Не верно. RFC4122 допускает только [1-5] для цифры версии и [89aAbB] для цифры варианта.
Брооф
6

Итак, я думаю, что Ричард Броноски на самом деле имеет лучший ответ на сегодняшний день, но я думаю, что вы можете сделать немного, чтобы сделать его несколько проще (или, по крайней мере, более кратким):

re_uuid = re.compile(r'[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}', re.I)
Кристофер Смит
источник
1
Еще круче:re_uuid = re.compile(r'[0-9a-f]{8}(?:-[0-9a-f]{4}){4}[0-9a-f]{8}', re.I)
Педро Джимено
5

Вариант для C ++:

#include <regex>  // Required include

...

// Source string    
std::wstring srcStr = L"String with GIUD: {4d36e96e-e325-11ce-bfc1-08002be10318} any text";

// Regex and match
std::wsmatch match;
std::wregex rx(L"(\\{[A-F0-9]{8}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{12}\\})", std::regex_constants::icase);

// Search
std::regex_search(srcStr, match, rx);

// Result
std::wstring strGUID       = match[1];
Антон К
источник
5

Для UUID, сгенерированного в OS X с uuidgen, шаблон регулярного выражения

[A-F0-9]{8}-[A-F0-9]{4}-4[A-F0-9]{3}-[89AB][A-F0-9]{3}-[A-F0-9]{12}

Проверить с помощью

uuidgen | grep -E "[A-F0-9]{8}-[A-F0-9]{4}-4[A-F0-9]{3}-[89AB][A-F0-9]{3}-[A-F0-9]{12}"
Quanlong
источник
2
$UUID_RE = join '-', map { "[0-9a-f]{$_}" } 8, 4, 4, 4, 12;

Кстати, разрешение только 4 на одну из позиций действительно только для UUIDv4. Но v4 не единственная версия UUID, которая существует. Я встречал v1 в своей практике.

abufct
источник
1

Если вы используете Posix Regex ( grep -E, MySQL и т. Д.), Это может быть проще для чтения и запоминания:

[[:xdigit:]]{8}(-[[:xdigit:]]{4}){3}-[[:xdigit:]]{12}
WALF
источник
0

Для Баш:

grep -E "[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89aAbB][a-f0-9]{3}-[a-f0-9]{12}"

Например:

$> echo "f2575e6a-9bce-49e7-ae7c-bff6b555bda4" | grep -E "[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89aAbB][a-f0-9]{3}-[a-f0-9]{12}"
f2575e6a-9bce-49e7-ae7c-bff6b555bda4
asherbar
источник