Пошук UUID в тексті з регулярним виразом


224

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

Чи може хтось придумати випадок використання, коли це припущення було б недійсним і змусило б я пропустити деякі UUID?


Це запитання від 6 років тому мало допомогти мені з проектом знайти кредитні картки у тексті. Згодом я відкрив код, який посилається на мій пост у блозі, в якому пояснюється нюанс, який викликали UUID під час пошуку кредитних карт guyellisrocks.com/2013/11/…
Хлопець

4
Пошук відповідності шаблону регулярних виразів UUID привів мене до цієї публікації переповнення стека, але прийнята відповідь насправді не є відповіддю. Крім того, посилання, яке ви вказали в коментарі під вашим запитанням, також не має шаблону (якщо я щось не пропускаю). Чи є одна з цих відповідей чимось, що ви закінчили використовувати?
Tass

Якщо ви слідуєте за кроликами, що починаються з посилань, починаючи з тієї, яку я розмістив, ви можете натрапити на цей рядок у GitHub, у якому є регекс, який я нарешті використав. (Зрозуміло, що важко знайти.) Цей код та цей файл можуть допомогти вам: github.com/guyellis/CreditCard/blob/master/Company.CreditCard/…
Хлопець

1
Жоден із цих відповідей, здається, не дає єдиного регулярного вираження для всіх варіантів лише дійсних UUID RFC 4122. Але схоже, що така відповідь була надана тут: stackoverflow.com/a/13653180/421049
Гаррет Вілсон,

Відповіді:


41

Я погоджуюся, що за визначенням ваш регекс не пропускає жодного UUID. Однак може бути корисним зазначити, що якщо ви шукаєте спеціально для глобальних унікальних ідентифікаторів Microsoft (GUID), для 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").
Панос

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]! Як це шістнадцять! Ваш регулярний вираз (як є) може повернути помилкові позитиви.
ексгума

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}/

Я не думаю, що ти маєш на увазі аз.
Бруно Броноський

8
Також потрібно прийняти [AF]. У розділі 3 RFC4122: "Шістнадцяткові значення" a "через" f "виводяться як малі регістри та є нечутливими до входу ". Також (:?8|9|A|B), мабуть, трохи читабельніше, як[89aAbB]
broofa

1
Потрібно скопіювати модифікацію @ broofa; як ваш виключає малі
регістри

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сферою застосування.
Paweł Psztyć

27
iВ кінці регулярного виразу позначає його як нечутливі до регістру.
johnhaley81

Модифікатор шаблону не завжди може бути використаний. Наприклад, у визначенні openapi, модель є чутливою до регістру
Стефан Яніко

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
Tony Sepia

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
Travis Stevens

@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']

Це робить найпростіший регулярний вираз UUID Python:

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


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}"

2
$UUID_RE = join '-', map { "[0-9a-f]{$_}" } 8, 4, 4, 4, 12;

BTW, що допускає лише 4 на одній з позицій, справедливий лише для UUIDv4. Але v4 - не єдина версія UUID, яка існує. Я також зустрічав v1 у своїй практиці.


1

Якщо використовується Pogex regex ( grep -E, MySQL тощо), це може бути простіше для читання та запам'ятовування:

[[:xdigit:]]{8}(-[[:xdigit:]]{4}){3}-[[:xdigit:]]{12}

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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.