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?

Chłopak
źródło
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}}" 
Panos
źródło
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
Ivelin
źródło
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 :)

Matthew F. Robben
źródło
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}/
Gajus
źródło
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
Ivan Gabriele
źródło
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.

iGEL
źródło
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}.

JimP
źródło
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.)

Bruno Bronosky
źródło
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

pix0r
źródło
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)
Christopher Smith
źródło
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];
Anton K
źródło
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}"
Quanlong
źródło
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.

abufct
źródło
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}
Walf
źródło
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
asherbar
źródło