Suche nach UUIDs in Text mit Regex


224

Ich suche nach UUIDs in Textblöcken mit einem regulären Ausdruck. Derzeit gehe ich davon aus, dass alle UUIDs einem Muster von 8-4-4-4-12 hexadezimalen Ziffern folgen.

Kann sich jemand einen Anwendungsfall vorstellen, bei dem diese Annahme ungültig wäre und dazu führen würde, dass ich einige UUIDs verpasse?


Diese Frage von vor 6 Jahren sollte mir bei einem Projekt helfen, Kreditkarten in einem Textblock zu finden. Ich habe anschließend den Code aus meinem Blog-Beitrag als Open-Source-Code verwendet, der die Nuancen erklärt, die die UUIDs bei der Suche nach Kreditkarten verursacht haben. Guyellisrocks.com/2013/11/…
Guy

4
Eine Suche nach UUID-Mustern für reguläre Ausdrücke brachte mich zu diesem Stapelüberlauf-Beitrag, aber die akzeptierte Antwort ist eigentlich keine Antwort. Außerdem hat der Link, den Sie im Kommentar unter Ihrer Frage angegeben haben, nicht das Muster (es sei denn, ich vermisse etwas). Ist eine dieser Antworten etwas, das Sie letztendlich verwendet haben?
Tass

Wenn Sie dem Kaninchengewirr von Links folgen, das mit dem von mir geposteten beginnt, stoßen Sie möglicherweise auf diese Zeile in GitHub, die den regulären Ausdruck enthält, den ich schließlich verwendet habe. (Verständlich, dass es schwer zu finden ist.) Dieser Code und diese Datei könnten Ihnen helfen: github.com/guyellis/CreditCard/blob/master/Company.CreditCard/…
Guy

1
Keine dieser Antworten scheint einen einzigen regulären Ausdruck für alle Varianten nur gültiger RFC 4122-UUIDs zu geben. Aber es sieht so aus, als ob eine solche Antwort hier gegeben wurde: stackoverflow.com/a/13653180/421049
Garret Wilson

Antworten:


41

Ich bin damit einverstanden, dass Ihre Regex per Definition keine UUID übersieht. Es kann jedoch hilfreich sein zu beachten, dass es bei der Suche nach GUIDs (Global Unique Identifiers) von Microsoft fünf äquivalente Zeichenfolgendarstellungen für eine GUID gibt:

"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
Unter welchen Situationen würde das erste Muster gefunden werden? dh Gibt es eine .Net-Funktion, die die Bindestriche entfernt oder die GUID ohne Bindestriche zurückgibt?
Guy

1
Sie können es mit myGuid.ToString ("N") erhalten.
Panos

461

Der reguläre Ausdruck für uuid lautet:

\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
mach das [a-f0-9]! Da ist es hex! Ihr Regex (so wie er ist) könnte falsch positive Ergebnisse zurückgeben.
Exhuma

13
In einigen Fällen möchten Sie vielleicht sogar [a-fA-F0-9] oder [A-F0-9] machen.
Hans-Peter Störr

22
@ cyber-monk: [0-9a-f] ist in Bedeutung und Geschwindigkeit identisch mit [a-f0-9] und [0123456789abcdef], da der reguläre Ausdruck ohnehin in eine Zustandsmaschine umgewandelt wird, wobei jede hexadezimale Ziffer in eine umgewandelt wird Eintrag in eine Zustandstabelle. Einen Einstieg in die Funktionsweise finden Sie unter en.wikipedia.org/wiki/Nondeterministic_finite_automaton
JesperSM

10
Diese Lösung ist nicht ganz richtig. Es werden IDs mit ungültigen Versions- und Variantenzeichen gemäß RFC4122 abgeglichen. Die Lösung von @Gajus ist in dieser Hinsicht korrekter. Außerdem erlaubt der RFC die Eingabe von Großbuchstaben, sodass das Hinzufügen von [AF] angemessen wäre.
Broofa

4
@broofa, ich sehe, dass Sie wirklich auf alle festgelegt sind, die nur UUIDs entsprechen, die mit dem RFC übereinstimmen. Ich denke jedoch, dass die Tatsache, dass Sie so oft darauf hinweisen mussten, ein solider Indikator ist, dass nicht alle UUIDs die RFC-Versions- und Variantenindikatoren verwenden. Die UUID-Definition en.wikipedia.org/wiki/Uuid#Definition gibt ein einfaches 8-4-4-4-12-Muster und 2 ^ 128 Möglichkeiten an. Der RFC repräsentiert nur eine Teilmenge davon. Also, was möchtest du zusammenbringen? Die Teilmenge oder alle?
Bruno Bronosky

120

@ivelin: UUID kann Großbuchstaben haben. Sie müssen also entweder den String toLowerCase () verwenden oder Folgendes verwenden:

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

Hätte das nur kommentiert aber nicht genug rep :)


22
Normalerweise können Sie damit umgehen, indem Sie das Muster mit einem i nach dem Muster als unabhängig von Groß- und Kleinschreibung definieren. Dies führt zu einem saubereren Muster: / [0-9a-f] {8} - [0-9a-f] {4} - [0 -9a-f] {4} - [0-9a-f] {4} - [0-9a-f] {12} / i
Thomas Bindzus

@ThomasBindzus Diese Option ist nicht in allen Sprachen verfügbar. Das ursprüngliche Muster in dieser Antwort funktionierte für mich in Go. Die /.../iVersion hat nicht.
Chris Redford

110

UUIDs der Version 4 haben die Form xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx, wobei x eine beliebige hexadezimale Ziffer und y eine von 8, 9, A oder B ist, z. B. f47ac10b-58cc-4372-a567-0e02b2c3d479.

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

Daher ist dies technisch korrekter:

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

Ich glaube nicht, dass du az meinst.
Bruno Bronosky

8
Müssen auch [AF] akzeptieren. Gemäß Abschnitt 3 von RFC4122: 'Die Hexadezimalwerte "a" bis "f" werden als Kleinbuchstaben ausgegeben und bei der Eingabe wird die Groß- und Kleinschreibung nicht berücksichtigt. ' Auch (:?8|9|A|B)ist wahrscheinlich etwas besser lesbar als[89aAbB]
broofa

1
Die Änderung von @ broofa muss kopiert werden. wie Ihre Kleinbuchstaben A oder B ausschließt.
ELLIOTTCABLE

6
@elliottcable Verwenden Sie je nach Umgebung einfach das iFlag (ohne Berücksichtigung der Groß- und Kleinschreibung).
Gajus

20
Sie lehnen die Versionen 1 bis 3 und 5 ab. Warum?
iGEL

90

Wenn Sie eine bestimmte UUID-Version überprüfen oder validieren möchten , finden Sie hier die entsprechenden regulären Ausdrücke.

Beachten Sie, dass der einzige Unterschied die Versionsnummer ist , die im 4.1.3. VersionKapitel von UUID 4122 RFC erläutert wird .

Die Versionsnummer ist das erste Zeichen der dritten Gruppe [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

Die Muster enthalten keine Kleinbuchstaben. Es sollte a-fneben jedem A-FBereich auch enthalten .
Paweł Psztyć

27
Das iam Ende des regulären Ausdrucks wird als Groß- und Kleinschreibung nicht berücksichtigt.
Johnhaley81

Ein Mustermodifikator kann nicht immer verwendet werden. In einer Openapi-Definition wird beispielsweise zwischen Groß- und Kleinschreibung unterschieden
Stephane Janicaud,

1
@StephaneJanicaud In OpenAPI sollten Sie den formatModifikator lieber verwenden, indem Sie ihn auf "uuid" setzen, anstatt einen regulären Ausdruck
Ivan Gabriele

Vielen Dank an @IvanGabriele für den Tipp, es war nur ein Beispiel, es ist das gleiche Problem, wenn Sie kein Muster ohne Berücksichtigung der Groß- und Kleinschreibung überprüfen möchten.
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

Gajus 'regulärer Ausdruck lehnt UUID V1-3 und 5 ab, obwohl sie gültig sind.


1
Es erlaubt jedoch ungültige Versionen (wie 8 oder A) und ungültige Varianten.
Brice

Beachten Sie, dass AB in [89AB] [0-9a-f] in Großbuchstaben und die restlichen zulässigen Zeichen in Kleinbuchstaben geschrieben sind. Es hat mich in Python erwischt
Tony Sepia

17

[\w]{8}(-[\w]{4}){3}-[\w]{12} hat in den meisten Fällen für mich gearbeitet.

Oder wenn Sie wirklich spezifisch sein wollen [\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12}.


3
Es ist erwähnenswert, dass \ w, zumindest in Java, sowohl mit _ als auch mit hexadezimalen Ziffern übereinstimmt. Das Ersetzen von \ w durch \ p {XDigit} ist möglicherweise besser geeignet, da dies die POSIX-Klasse ist, die für den Abgleich von hexadezimalen Ziffern definiert ist. Dies kann bei Verwendung anderer Unicode-Zeichensätze auftreten.
oconnor0

1
@oconnor \wbedeutet normalerweise "Wortzeichen". Es stimmt viel mehr als mit Hex-Ziffern überein. Ihre Lösung ist viel besser. Oder für Kompatibilität / Lesbarkeit könnten Sie verwenden[a-f0-9]
Exhuma

1
Hier ist eine Zeichenfolge, die wie eine Regex aussieht und mit diesen Mustern übereinstimmt, aber eine ungültige Regex ist: 2wtu37k5-q174-4418-2cu2-276e4j82sv19
Travis Stevens

@OleTraveler nicht wahr, funktioniert wie ein Zauber. 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 Diese Zeichenfolge (2wt ...) ist eine ungültige UUID, aber das in dieser Antwort angegebene Muster stimmt mit dieser Zeichenfolge überein, die fälschlicherweise angibt, dass es sich um eine gültige UUID handelt. Es ist schade, dass ich mich nicht erinnere, warum diese UUID ungültig ist.
Travis Stevens

10

In Python Re können Sie von numerischen bis zu Großbuchstaben Alpha wechseln. So..

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

Das macht den einfachsten Python-UUID-Regex:

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

Ich überlasse es dem Leser als Übung, timeit zu verwenden, um die Leistung dieser zu vergleichen.

Genießen. Behalte es Pythonic ™!

HINWEIS: Diese Bereiche stimmen auch überein :;<=>?@'. Wenn Sie den Verdacht haben, dass dies zu falsch positiven Ergebnissen führen könnte, verwenden Sie nicht die Verknüpfung. (Vielen Dank an Oliver Aubert, der in den Kommentaren darauf hingewiesen hat.)


2
[0-F] stimmt zwar mit 0-9 und AF überein, aber auch mit jedem Zeichen, dessen ASCII-Code zwischen 57 (für 9) und 65 (für A) liegt, dh eines von :; <=>? @ '.
Olivier Aubert

7
Verwenden Sie den oben genannten Code nur, wenn Sie Folgendes berücksichtigen möchten: => ;? <;: - <@ =: - @ =; = - @; @: -> == @?> = :? = @; als gültige UUID :-)
Olivier Aubert

9

Per Definition besteht eine UUID aus 32 hexadezimalen Ziffern, die wie beschrieben in 5 Gruppen durch Bindestriche getrennt sind. Sie sollten keine mit Ihrem regulären Ausdruck verpassen.

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


2
Nicht richtig. RFC4122 erlaubt nur [1-5] für die Versionsziffer und [89aAbB] für die Variantenziffer.
Broofa

6

Ich denke, Richard Bronosky hat tatsächlich die bisher beste Antwort, aber ich denke, Sie können ein wenig tun, um es etwas einfacher (oder zumindest kürzer) zu machen:

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

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

5

Variante für 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

Für UUID, die unter OS X mit generiert wurde uuidgen, lautet das Regex-Muster

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

Überprüfen Sie mit

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;

Übrigens, nur 4 auf einer der Positionen zuzulassen, gilt nur für UUIDv4. V4 ist jedoch nicht die einzige existierende UUID-Version. Ich habe v1 auch in meiner Praxis getroffen.


1

Wenn Sie Posix Regex ( grep -E, MySQL usw.) verwenden, ist dies möglicherweise einfacher zu lesen und zu merken:

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

0

Für 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}"

Beispielsweise:

$> 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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.