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?

Chico
fuente
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}}" 
Panos
fuente
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
Ivelin
fuente
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 :)

Matthew F. Robben
fuente
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}/
Gajus
fuente
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
Ivan Gabriele
fuente
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.

iGEL
fuente
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}.

Pobre
fuente
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).

Bruno Bronosky
fuente
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

pix0r
fuente
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)
Christopher Smith
fuente
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];
Anton K
fuente
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}"
Quanlong
fuente
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.

abufct
fuente
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}
Walf
fuente
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
asherbar
fuente