Wyszukiwanie UUID w tekście za pomocą wyrażenia regularnego


224

Szukam UUID w blokach tekstu za pomocą wyrażenia regularnego. Obecnie opieram się na założeniu, że wszystkie UUID będą miały wzór 8-4-4-4-12 cyfr szesnastkowych.

Czy ktoś może pomyśleć o przypadku użycia, w którym to założenie byłoby nieważne i spowodowałoby, że przegapiłem niektóre UUID?


To pytanie sprzed 6 lat miało mi pomóc w projekcie znalezienia kart kredytowych w bloku tekstu. Następnie otworzyłem kod źródłowy, który jest link do mojego postu na blogu, który wyjaśnia niuanse, jakie powodowały UUID podczas wyszukiwania kart kredytowych guyellisrocks.com/2013/11/…
Guy

4
Poszukiwanie dopasowania wzorca wyrażenia regularnego UUID doprowadziło mnie do tego przepełnienia stosu, ale zaakceptowana odpowiedź tak naprawdę nie jest odpowiedzią. Ponadto link podany w komentarzu poniżej pytania również nie ma wzorca (chyba że czegoś mi brakuje). Czy jedna z tych odpowiedzi jest czymś, czego użyłeś?
Tass

Jeśli podążasz za króliczym ostrzeżeniem linków zaczynającym się od tego, który opublikowałem, możesz natknąć się na tę linię w GitHub, która ma regex, którego w końcu użyłem. (Zrozumiałe, że trudno je znaleźć.) Ten kod i ten plik mogą ci pomóc: github.com/guyellis/CreditCard/blob/master/Company.CreditCard/...
Guy

1
Żadna z tych odpowiedzi nie wydaje się zawierać jednego wyrażenia regularnego dla wszystkich wariantów tylko ważnych UUID RFC 4122. Ale wygląda na to, że taka odpowiedź została podana tutaj: stackoverflow.com/a/13653180/421049
Garret Wilson

Odpowiedzi:


41

Zgadzam się, że z definicji wyrażenie regularne nie zawiera żadnego identyfikatora UUID. Warto jednak zauważyć, że jeśli szukasz szczególnie unikatowych identyfikatorów globalnych (GUID) firmy Microsoft, istnieje pięć równoważnych ciągów znaków dla identyfikatora 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
W jakich sytuacjach można znaleźć pierwszy wzór? tj. Czy istnieje funkcja .Net, która usuwałaby łączniki lub zwracała identyfikator GUID bez łączników?
Guy

1
Możesz go pobrać za pomocą myGuid.ToString („N”).
Panos,

462

Wyrażenie regularne dla uuid to:

\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
zrób to [a-f0-9]! Jak to hex! Twoje wyrażenie regularne (tak jak jest) może zwracać fałszywe alarmy.
ekshuma

13
W niektórych przypadkach możesz nawet chcieć zrobić to [a-fA-F0-9] lub [A-F0-9].
Hans-Peter Störr

22
@ cyber-monk: [0-9a-f] jest identyczny z [a-f0-9] i [0123456789abcdef] w znaczeniu i szybkości, ponieważ regex jest i tak przekształcany w maszynę stanu, a każda cyfra szesnastkowa zamieniana jest w wpis w tabeli stanów. Aby dowiedzieć się, jak to działa, zobacz en.wikipedia.org/wiki/Nondeterministic_finite_automaton
JesperSM,

10
To rozwiązanie nie jest całkiem poprawne. Pasuje do identyfikatorów, które mają niepoprawną wersję i znaki wariantu zgodnie z RFC4122. Rozwiązanie @Gajus jest w tym względzie bardziej poprawne. Ponadto RFC zezwala na wprowadzanie dużych liter na wejściu, więc dodanie [AF] byłoby właściwe.
broofa

4
@ Broofa, widzę, że naprawdę jesteś nastawiony na wszystkich pasujących tylko UUID, które są zgodne z RFC. Myślę jednak, że fakt, że musiałeś to wskazywać tyle razy, jest solidnym wskaźnikiem, że nie wszystkie UUID będą używać wersji RFC i wskaźników wariantów. Definicja UUID en.wikipedia.org/wiki/Uuid#Definition określa prosty wzorzec 8-4-4-4-12 i 2 ^ 128 możliwości. RFC reprezentuje tylko jego podzbiór. Więc co chcesz dopasować? Podzbiór, czy wszystkie?
Bruno Bronosky,

120

@ivelin: UUID może mieć wielkie litery. Musisz albo toLowerCase () napis lub użyć:

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

Po prostu skomentowałbym to, ale za mało rep :)


22
Zwykle można sobie z tym poradzić, definiując wzorzec jako niewrażliwy na wielkość liter za i po wzorcu, co czyni czystszy wzorzec: / [0-9a-f] {8} - [0-9a-f] {4} - [0 -9a-f] {4} - [0-9a-f] {4} - [0-9a-f] {12} / i
Thomas Bindzus

@ThomasBindzus Ta opcja nie jest dostępna we wszystkich językach. Oryginalny wzór w tej odpowiedzi zadziałał dla mnie w Go. /.../iWersja nie.
Chris Redford

110

Identyfikatory UUID w wersji 4 mają postać xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx, gdzie x to dowolna cyfra szesnastkowa, ay to jeden z 8, 9, A lub B. np. F47ac10b-58cc-4372-a567-0e02b2c3d479.

źródło: http://en.wikipedia.org/wiki/Uuid#Definition

Dlatego jest to technicznie bardziej poprawne:

/[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89aAbB][a-f0-9]{3}-[a-f0-9]{12}/

Nie sądzę, że masz na myśli az.
Bruno Bronosky,

8
Musisz również zaakceptować [AF]. Zgodnie z sekcją 3 RFC4122: „Wartości szesnastkowe od„ a ”do„ f ”są wyprowadzane jako małe litery i przy wprowadzaniu nie są rozróżniane małe i wielkie litery ”. (:?8|9|A|B)Prawdopodobnie jest też nieco bardziej czytelny, ponieważ[89aAbB]
Broofa

1
Musisz skopiować modyfikację @ broofa; ponieważ twój wyklucza małe litery A lub B.
ELLIOTTCABLE

6
@elliottcable W zależności od środowiska użyj iflagi (bez rozróżniania wielkości liter).
Gajus

20
Odrzucasz wersję od 1 do 3 i 5. Dlaczego?
iGEL

90

Jeśli chcesz sprawdzić lub sprawdzić konkretną wersję UUID , oto odpowiednie wyrażenia regularne.

Zauważ, że jedyną różnicą jest numer wersji , który wyjaśniono w 4.1.3. Versionrozdziale UUID 4122 RFC .

Numer wersji to pierwszy znak trzeciej grupy [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

Wzory nie zawierają małych liter. Powinien także zawierać a-fobok każdego A-Fzakresu.
Paweł Psztyć

27
iNa końcu znaków regex go jako wielkość liter ma znaczenie.
johnhaley81

Nie zawsze można zastosować modyfikator wzoru. Na przykład w definicji openapi we wzorcu rozróżniana jest wielkość liter
Stephane Janicaud

1
@StephaneJanicaud W OpenAPI powinieneś raczej użyć formatmodyfikatora ustawiając go na „uuid” zamiast używać wyrażenia regularnego do testowania UUID: swagger.io/docs/specification/data-models/data-types/#format
Ivan Gabriele

Dziękuję @IvanGabriele za wskazówkę, to był tylko przykład, to ten sam problem, gdy nie chcesz sprawdzać żadnego wzoru bez rozróżniania wielkości liter.
Stephane Janicaud

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

Wyrażenie regularne Gajusa odrzuca UUID V1-3 i 5, nawet jeśli są poprawne.


1
Ale dopuszcza nieprawidłowe wersje (jak 8 lub A) i nieprawidłowe warianty.
Brice

Zauważ, że AB w [89AB] [0-9a-f] to wielkie litery, a reszta dozwolonych znaków to małe litery. Przyłapał mnie w Pythonie
Tony Sepia

17

[\w]{8}(-[\w]{4}){3}-[\w]{12} pracował dla mnie w większości przypadków.

Lub jeśli chcesz być naprawdę konkretny [\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12}.


3
Warto zauważyć, że \ w, przynajmniej w Javie, odpowiada _ oraz cyfrom szesnastkowym. Zastąpienie \ w \ p {XDigit} może być bardziej odpowiednie, ponieważ jest to klasa POSIX zdefiniowana dla pasujących cyfr szesnastkowych. Może się to zepsuć podczas korzystania z innych zestawów znaków Unicode.
oconnor0

1
@oconnor \wzwykle oznacza „znaki słowne”. Będzie pasować znacznie więcej niż cyfr szesnastkowych. Twoje rozwiązanie jest znacznie lepsze. Lub, dla kompatybilności / czytelności, której możesz użyć[a-f0-9]
ekshuma

1
Oto ciąg znaków, który wygląda jak wyrażenie regularne i pasuje do tych wzorców, ale jest nieprawidłowym wyrażeniem regularnym: 2wtu37k5-q174-4418-2cu2-276e4j82sv19
Travis Stevens

@OleTraveler nieprawda, działa jak urok. 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')
Tomasz Wojcik,

3
@tom Ten ciąg (2wt ...) jest nieprawidłowym UUID, ale wzorzec podany w tej odpowiedzi pasuje do tego ciągu, wskazując fałszywie, że jest to prawidłowy UUID. Szkoda, że ​​nie pamiętam, dlaczego ten UUID jest nieprawidłowy.
Travis Stevens,

10

W Python Re można rozciągać od alfabetu na duże litery. Więc..

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

To sprawia, że ​​najprostsze wyrażenie regularne UUID w Pythonie:

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

Zostawię to jako ćwiczenie dla czytelnika, aby użyć timeit do porównania ich wydajności.

Cieszyć się. Keep it Pythonic ™!

UWAGA: Te zakresy również będą pasować, :;<=>?@'więc jeśli podejrzewasz, że może to dać fałszywe alarmy, nie bierz skrótu. (Dziękuję Oliverowi Aubertowi za wskazanie tego w komentarzach.)


2
[0-F] rzeczywiście pasuje do 0-9 i AF, ale także do każdego znaku, którego kod ASCII zawiera się między 57 (dla 9) a 65 (dla A), to znaczy dowolną z:; <=>? @ '.
Olivier Aubert

7
Więc nie używaj wyżej wspomnianego kodu, chyba że chcesz rozważyć: =>;? <;: - <@ =: - @ =; = - @; @: -> == @?> =:? = @; jako ważny UUID :-)
Olivier Aubert

9

Z definicji UUID składa się z 32 cyfr szesnastkowych, oddzielonych w 5 grupach łącznikami, tak jak opisano. Nie powinieneś przegapić żadnego z wyrażeniem regularnym.

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


2
Niepoprawne. RFC4122 dopuszcza tylko [1-5] dla cyfry wersji i [89aAbB] dla cyfry wariantu.
broofa

6

Tak więc, myślę, że Richard Bronosky rzeczywiście ma najlepszą jak do tej pory odpowiedź, ale myślę, że możesz zrobić trochę, aby uczynić to nieco prostszym (lub przynajmniej krótszym):

re_uuid = re.compile(r'[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}', re.I)

1
Jeszcze terser:re_uuid = re.compile(r'[0-9a-f]{8}(?:-[0-9a-f]{4}){4}[0-9a-f]{8}', re.I)
Pedro Gimeno

5

Wariant dla 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

W przypadku identyfikatora UUID wygenerowanego w systemie OS X za uuidgenpomocą wzorca wyrażenia regularnego jest

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

Zweryfikuj za pomocą

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, dopuszczenie tylko 4 na jednej pozycji jest ważne tylko dla UUIDv4. Ale v4 nie jest jedyną istniejącą wersją UUID. W mojej praktyce spotkałem również v1.


1

Jeśli używasz wyrażenia regularnego Posix ( grep -E, MySQL itp.), Może to być łatwiejsze do odczytania i zapamiętania:

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

0

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

Na przykład:

$> 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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.