Búsqueda de UUID en texto con expresiones regulares


224

Estoy buscando UUID en bloques de texto usando una expresión regular. Actualmente confío en el supuesto de que todos los UUID seguirán un patrón de 8-4-4-4-12 dígitos hexadecimales.

¿Alguien puede pensar en un caso de uso donde esta suposición no sea válida y me haga perder algunos UUID?


Esta pregunta de hace 6 años fue para ayudarme con un proyecto para encontrar tarjetas de crédito en un bloque de texto. Posteriormente, he abierto el código que está vinculado desde mi publicación de blog que explica el matiz que los UUID estaban causando al buscar tarjetas de crédito guyellisrocks.com/2013/11/…
Guy

44
Una búsqueda de coincidencia de patrón de expresión regular UUID me llevó a esta publicación de desbordamiento de pila, pero la respuesta aceptada en realidad no es una respuesta. Además, el enlace que proporcionó en el comentario debajo de su pregunta tampoco tiene el patrón (a menos que me falte algo). ¿Una de estas respuestas es algo que terminaste usando?
Tass

Si sigues el laberinto de enlaces que comienza con el que publiqué, podrías encontrar esta línea en GitHub que tiene la expresión regular que finalmente utilicé. (Es comprensible que sea difícil de encontrar.) Ese código y ese archivo podrían ayudarlo: github.com/guyellis/CreditCard/blob/master/Company.CreditCard/…
Guy

1
Ninguna de estas respuestas parece dar una expresión regular única para todas las variantes de solo UUID RFC 4122 válidos. Pero parece que aquí se dio una respuesta: stackoverflow.com/a/13653180/421049
Garret Wilson

Respuestas:


41

Estoy de acuerdo en que, por definición, su expresión regular no pierde ningún UUID. Sin embargo, puede ser útil tener en cuenta que si está buscando especialmente los identificadores únicos globales (GUID) de Microsoft, hay cinco representaciones de cadena equivalentes para un 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
¿Bajo qué situaciones se encontraría el primer patrón? es decir, ¿hay una función .Net que elimine los guiones o devuelva el GUID sin guiones?
Guy

1
Puede obtenerlo con myGuid.ToString ("N").
Panos

462

La expresión regular para uuid es:

\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
haz eso [a-f0-9]! Como es hechizo! Su expresión regular (tal como está) podría devolver falsos positivos.
exhuma

13
En algunos casos, es posible que desee hacer eso [a-fA-F0-9] o [A-F0-9].
Hans-Peter Störr

22
@ cyber-monk: [0-9a-f] es idéntico a [a-f0-9] y [0123456789abcdef] en significado y velocidad, ya que la expresión regular se convierte en una máquina de estados de todos modos, con cada dígito hexadecimal convertido en un entrada en una tabla de estado. Para un punto de entrada sobre cómo funciona esto, vea en.wikipedia.org/wiki/Nondeterministic_finite_automaton
JesperSM

10
Esta solución no es del todo correcta. Coincide con ID que tienen versiones no válidas y caracteres variantes según RFC4122. La solución de @Gajus es más correcta en ese sentido. Además, el RFC permite caracteres en mayúscula en la entrada, por lo que sería apropiado agregar [AF].
broofa

44
@broofa, veo que realmente está configurado para que todos coincidan solo con UUID que sean consistentes con el RFC. Sin embargo, creo que el hecho de que haya tenido que señalar esto tantas veces es un indicador sólido de que no todos los UUID utilizarán la versión RFC y los indicadores de variantes. La definición de UUID en.wikipedia.org/wiki/Uuid#Definition establece un patrón simple 8-4-4-4-12 y 2 ^ 128 posibilidades. El RFC representa solo un subconjunto de eso. Entonces, ¿qué quieres hacer coincidir? ¿El subconjunto o todos ellos?
Bruno Bronosky

120

@ivelin: UUID puede tener mayúsculas. Por lo tanto, necesitará toLowerCase () la cadena o usar:

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

Hubiera comentado esto pero no suficiente representante :)


22
Por lo general, puede manejar esto definiendo el patrón como insensible a mayúsculas y minúsculas con una i después del patrón, esto hace un patrón más limpio: / [0-9a-f] {8} - [0-9a-f] {4} - [0 -9a-f] {4} - [0-9a-f] {4} - [0-9a-f] {12} / i
Thomas Bindzus

@ThomasBindzus Esa opción no está disponible en todos los idiomas. El patrón original en esta respuesta funcionó para mí en Go. La /.../iversión no lo hizo.
Chris Redford

110

Los UUID de la versión 4 tienen la forma xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx donde x es cualquier dígito hexadecimal e y es uno de 8, 9, A o B. por ejemplo, f47ac10b-58cc-4372-a567-0e02b2c3d479.

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

Por lo tanto, esto es técnicamente más correcto:

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

No creo que te refieras a az.
Bruno Bronosky

8
Necesito aceptar [AF] también. Según la sección 3 de RFC4122: 'Los valores hexadecimales "a" a "f" se muestran como caracteres en minúscula y no distinguen entre mayúsculas y minúsculas en la entrada ". También (:?8|9|A|B)es probablemente un poco más legible como[89aAbB]
broofa

1
Necesita copiar la modificación de @ broofa; como el suyo excluye las minúsculas A o B.
ELLIOTTCABLE

66
@elliottcable Dependiendo de su entorno, solo use el distintivo i(sin distinción entre mayúsculas y minúsculas).
Gajus

20
Estás rechazando las versiones 1 a 3 y 5. ¿Por qué?
iGEL

90

Si desea verificar o validar una versión específica de UUID , aquí están las expresiones regulares correspondientes.

Tenga en cuenta que la única diferencia es el número de versión , que se explica en el 4.1.3. Versioncapítulo de UUID 4122 RFC .

El número de versión es el primer carácter del tercer grupo [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

Los patrones no incluyen letras minúsculas. También debe contener al a-flado de cada A-Fámbito.
Paweł Psztyć

27
El ifinal de la expresión regular lo marca como mayúsculas y minúsculas.
johnhaley81

Un modificador de patrón no siempre se puede usar. Por ejemplo, en una definición de openapi, el patrón distingue entre mayúsculas y minúsculas
Stephane Janicaud,

1
@StephaneJanicaud En OpenAPI, debería usar el formatmodificador configurándolo en "uuid" en lugar de usar una expresión regular para probar UUID: swagger.io/docs/specification/data-models/data-types/#format
Ivan Gabriele

Gracias @IvanGabriele por el consejo, fue solo un ejemplo, es el mismo problema cuando no quieres verificar ningún patrón que no distinga entre mayúsculas y minúsculas.
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

La expresión regular de Gajus rechaza UUID V1-3 y 5, aunque sean válidos.


1
Pero permite versiones no válidas (como 8 o A) y variantes no válidas.
Brice

Tenga en cuenta que AB en [89AB] [0-9a-f] es mayúscula y el resto de los caracteres permitidos son minúsculas. Me ha pillado en Python
Tony Sepia

17

[\w]{8}(-[\w]{4}){3}-[\w]{12} me ha funcionado en la mayoría de los casos.

O si quieres ser realmente específico [\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12}.


3
Vale la pena señalar que \ w, en Java al menos, coincide con _ y con dígitos hexadecimales. Reemplazar \ w con \ p {XDigit} puede ser más apropiado, ya que es la clase POSIX definida para hacer coincidir dígitos hexadecimales. Esto puede romperse cuando se utilizan otros conjuntos de caracteres Unicode.
oconnor0

1
@oconnor \wgeneralmente significa "caracteres de palabras". Coincidirá mucho más que dígitos hexadecimales. Tu solución es mucho mejor. O, por compatibilidad / legibilidad, podría usar[a-f0-9]
exhuma

1
Aquí hay una cadena que parece una expresión regular y coincide con esos patrones, pero es una expresión regular no válida: 2wtu37k5-q174-4418-2cu2-276e4j82sv19
Travis Stevens

@OleTraveler no es cierto, funciona de maravilla. 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 Esa cadena (2wt ...) es un UUID no válido, pero el patrón dado en esta respuesta coincide con esa cadena que indica falsamente que es un UUID válido. Es una pena que no recuerde por qué ese UUID no es válido.
Travis Stevens

10

En python re, puede abarcar desde números numéricos a mayúsculas alfa. Entonces..

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

Eso hace que la expresión regular UUID de Python más simple:

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

Lo dejaré como un ejercicio para que el lector use timeit para comparar el rendimiento de estos.

Disfrutar. ¡Mantenlo Pythonic ™!

NOTA: Esos tramos también coincidirán :;<=>?@', por lo tanto, si sospecha que podría darle falsos positivos, no tome el atajo. (Gracias Oliver Aubert por señalar eso en los comentarios).


2
[0-F] coincidirá con 0-9 y AF, pero también con cualquier carácter cuyo código ASCII esté entre 57 (para 9) y 65 (para A), es decir, cualquiera de:; <=>? @ '.
Olivier Aubert

77
Por lo tanto, no use el código mencionado anteriormente, excepto si desea considerar: =>;? <;: - <@ =: - @ =; = - @; @: -> == @?> =:? = @; como UUID válido :-)
Olivier Aubert

9

Por definición, un UUID tiene 32 dígitos hexadecimales, separados en 5 grupos por guiones, tal como lo ha descrito. No debes perderte ninguno con tu expresión regular.

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


2
Incorrecto. RFC4122 solo permite [1-5] para el dígito de la versión y [89aAbB] para el dígito variante.
broofa

6

Entonces, creo que Richard Bronosky en realidad tiene la mejor respuesta hasta la fecha, pero creo que puede hacer un poco para que sea algo más simple (o al menos terser):

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

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

5

Variante para 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

Para UUID generado en OS X con uuidgen, el patrón regex es

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

Verificar con

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;

Por cierto, permitir solo 4 en una de las posiciones solo es válido para UUIDv4. Pero v4 no es la única versión de UUID que existe. También he conocido v1 en mi práctica.


1

Si usa Posix regex ( grep -E, MySQL, etc.), esto puede ser más fácil de leer y recordar:

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

0

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

Por ejemplo:

$> 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
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.