Поиск UUID в тексте с помощью регулярных выражений
Я ищу UUID в блоках текста с помощью регулярных выражений. В настоящее время я полагаюсь на предположение, что все UUID будут следовать шаблонам из 8-4-4-4-12 шестнадцатеричных цифр.
Кто-нибудь может вспомнить случай использования, когда это предположение было бы недействительным и заставило бы меня пропустить некоторые UUID?
20 ответов
Я согласен, что по определению ваше регулярное выражение не пропускает ни одного 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}}"
Регулярное выражение для 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
@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}
Только что прокомментировал это, но не достаточно репутации:)
Если вы хотите проверить или проверить конкретную версию 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
UUID версии 4 имеют форму xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx, где x - любая шестнадцатеричная цифра, а y - одна из 8, 9, A или B. Например, f47ac10b-58cc-4372-a567-0e02b2c3d479.
источник: http://en.wikipedia.org/wiki/Uuid
Следовательно, это технически более правильно:
/[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89aAbB][a-f0-9]{3}-[a-f0-9]{12}/
/^[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, даже если они действительны.
[\w]{8}(-[\w]{4}){3}-[\w]{12}
работал для меня в большинстве случаев.
Или если вы хотите быть действительно конкретным [\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12}
,
В 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™!
ПРИМЕЧАНИЕ. Эти промежутки также будут совпадать :;<=>?@'
поэтому, если вы подозреваете, что это может дать вам ложные срабатывания, не используйте ярлык. (Спасибо, Оливер Обер, за то, что указал на это в комментариях.)
По определению UUID - это 32 шестнадцатеричные цифры, разделенные на 5 групп дефисами, как вы уже описали. Вы не должны пропустить ни одного со своим регулярным выражением.
При использовании регулярного выражения Posix (grep -E
, MySQL и т. Д.), Это может быть легче прочитать и запомнить:
[[:xdigit:]]{8}(-[[:xdigit:]]{4}){3}-[[:xdigit:]]{12}
Изменить: разновидности Perl и PCRE также поддерживают классы символов Posix, так что это будет работать с ними. Для тех, измените(…)
к не захватывающей подгруппе (?:…)
.
Вот рабочий REGEX: https://www.regextester.com/99148
const regex = [0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}
Итак, я думаю, что Ричард Броноски на самом деле имеет лучший ответ на сегодняшний день, но я думаю, что вы можете сделать немного, чтобы сделать его несколько проще (или, по крайней мере, более кратким):
re_uuid = re.compile(r'[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}', re.I)
Для 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}"
Вариант для 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];
Для bash:
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
$UUID_RE = join '-', map { "[0-9a-f]{$_}" } 8, 4, 4, 4, 12;
Кстати, разрешение только 4 на одну из позиций действительно только для UUIDv4. Но v4 не единственная версия UUID, которая существует. Я встречал v1 и в моей практике.
Я просто хочу поделиться наименьшим способом регулярного выражения, чтобы сделать то же самое из хороших ответов здесь.
[a-f\d]{8}(-[a-f\d]{4}){3}-[a-f\d]{12}$
Пожалуйста, используйте с флагом игнорирования регистраi
для игнорирования регистра/без учета регистра:
const pattern = /^[a-f\d]{8}(-[a-f\d]{4}){3}-[a-f\d]{12}$/i // JavaScript
pattern = re.compile(r"^[a-f\d]{8}(-[a-f\d]{4}){3}-[a-f\d]{12}$", re.IGNORECASE) # Python
$pattern = '/^[a-f\d]{8}(-[a-f\d]{4}){3}-[a-f\d]{12}$/i' // php
Хотел внести свой вклад, так как мое регулярное выражение охватывает все случаи из OP и правильно группирует все соответствующие данные по методу группы (вам не нужно отправлять строку обработки, чтобы получить каждую часть uuid, это регулярное выражение уже получило это для вас )
([\d\w]{8})-?([\d\w]{4})-?([\d\w]{4})-?([\d\w]{4})-?([\d\w]{12})|[{0x]*([\d\w]{8})[0x, ]{4}([\d\w]{4})[0x, ]{4}([\d\w]{4})[0x, {]{5}([\d\w]{2})[0x, ]{4}([\d\w]{2})[0x, ]{4}([\d\w]{2})[0x, ]{4}([\d\w]{2})[0x, ]{4}([\d\w]{2})[0x, ]{4}([\d\w]{2})[0x, ]{4}([\d\w]{2})[0x, ]{4}([\d\w]{2})
Обобщите один, где подчеркивание также игнорируется должным образом и разрешены только буквенно-цифровые значения с шаблоном 8-4-4-4-12.
^[^\W_]{8}(-[^\W_]{4}){4}[^\W_]{8}$
или
^[^\W_]{8}(-[^\W_]{4}){3}-[^\W_]{12}$
оба дают одинаковый результат, но последний более читаем. И я хотел бы порекомендовать сайт, где можно научиться, а также правильно протестировать регулярное выражение: https://regexr.com/
Официальная библиотека uuid использует следующее регулярное выражение:
/^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i
См. ссылку