Expresión regular que coincide con direcciones IPv6 válidas

111

Tengo problemas para escribir una expresión regular que coincida con direcciones IPv6 válidas, incluidas aquellas en su forma comprimida (con ::ceros a la izquierda o omitidos de cada par de bytes).

¿Alguien puede sugerir una expresión regular que cumpla con el requisito?

Estoy considerando expandir cada par de bytes y hacer coincidir el resultado con una expresión regular más simple.

Solo lectura
fuente
1
Visite intermapper.com/ipv6validator .. enlaza con este script de prueba de Perl
Mottie
Probé todas las respuestas a continuación y no funcionan para todos mis casos de prueba y / o también incluyen IPv4 que no se solicitó. He descubierto que esta es la solución más limpia hasta ahora: stackoverflow.com/a/21944928/3112803
gfrobenius

Respuestas:

252

No pude hacer que la respuesta de @Factor Mystic funcionara con expresiones regulares POSIX, así que escribí una que funciona con expresiones regulares POSIX y expresiones regulares PERL.

Debería coincidir:

Expresión regular de IPv6:

(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))

Para facilitar la lectura, lo siguiente es la expresión regular anterior dividida en los puntos OR principales en líneas separadas:

# IPv6 RegEx
(
([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|          # 1:2:3:4:5:6:7:8
([0-9a-fA-F]{1,4}:){1,7}:|                         # 1::                              1:2:3:4:5:6:7::
([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|         # 1::8             1:2:3:4:5:6::8  1:2:3:4:5:6::8
([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|  # 1::7:8           1:2:3:4:5::7:8  1:2:3:4:5::8
([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|  # 1::6:7:8         1:2:3:4::6:7:8  1:2:3:4::8
([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|  # 1::5:6:7:8       1:2:3::5:6:7:8  1:2:3::8
([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|  # 1::4:5:6:7:8     1:2::4:5:6:7:8  1:2::8
[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|       # 1::3:4:5:6:7:8   1::3:4:5:6:7:8  1::8  
:((:[0-9a-fA-F]{1,4}){1,7}|:)|                     # ::2:3:4:5:6:7:8  ::2:3:4:5:6:7:8 ::8       ::     
fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|     # fe80::7:8%eth0   fe80::7:8%1     (link-local IPv6 addresses with zone index)
::(ffff(:0{1,4}){0,1}:){0,1}
((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}
(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|          # ::255.255.255.255   ::ffff:255.255.255.255  ::ffff:0:255.255.255.255  (IPv4-mapped IPv6 addresses and IPv4-translated addresses)
([0-9a-fA-F]{1,4}:){1,4}:
((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}
(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])           # 2001:db8:3:4::192.0.2.33  64:ff9b::192.0.2.33 (IPv4-Embedded IPv6 Address)
)

# IPv4 RegEx
((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])

Para facilitar la comprensión de lo anterior, el siguiente código "pseudo" replica lo anterior:

IPV4SEG  = (25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])
IPV4ADDR = (IPV4SEG\.){3,3}IPV4SEG
IPV6SEG  = [0-9a-fA-F]{1,4}
IPV6ADDR = (
           (IPV6SEG:){7,7}IPV6SEG|                # 1:2:3:4:5:6:7:8
           (IPV6SEG:){1,7}:|                      # 1::                                 1:2:3:4:5:6:7::
           (IPV6SEG:){1,6}:IPV6SEG|               # 1::8               1:2:3:4:5:6::8   1:2:3:4:5:6::8
           (IPV6SEG:){1,5}(:IPV6SEG){1,2}|        # 1::7:8             1:2:3:4:5::7:8   1:2:3:4:5::8
           (IPV6SEG:){1,4}(:IPV6SEG){1,3}|        # 1::6:7:8           1:2:3:4::6:7:8   1:2:3:4::8
           (IPV6SEG:){1,3}(:IPV6SEG){1,4}|        # 1::5:6:7:8         1:2:3::5:6:7:8   1:2:3::8
           (IPV6SEG:){1,2}(:IPV6SEG){1,5}|        # 1::4:5:6:7:8       1:2::4:5:6:7:8   1:2::8
           IPV6SEG:((:IPV6SEG){1,6})|             # 1::3:4:5:6:7:8     1::3:4:5:6:7:8   1::8
           :((:IPV6SEG){1,7}|:)|                  # ::2:3:4:5:6:7:8    ::2:3:4:5:6:7:8  ::8       ::       
           fe80:(:IPV6SEG){0,4}%[0-9a-zA-Z]{1,}|  # fe80::7:8%eth0     fe80::7:8%1  (link-local IPv6 addresses with zone index)
           ::(ffff(:0{1,4}){0,1}:){0,1}IPV4ADDR|  # ::255.255.255.255  ::ffff:255.255.255.255  ::ffff:0:255.255.255.255 (IPv4-mapped IPv6 addresses and IPv4-translated addresses)
           (IPV6SEG:){1,4}:IPV4ADDR               # 2001:db8:3:4::192.0.2.33  64:ff9b::192.0.2.33 (IPv4-Embedded IPv6 Address)
           )

Publiqué un script en GitHub que prueba la expresión regular: https://gist.github.com/syzdek/6086792

David M. Syzdek
fuente
3
Su expresión regular IPv4 no coincide con IP como127.000.000.001
Kentzo
21
Los segmentos de IPv4 no deben incluir ceros a la izquierda. Si hay un cero a la izquierda, el segmento de IPv4 debe interpretarse en octal. Entonces, el IPV4SEG anterior es correcto al no permitir '000'. Sin embargo, permite '00', que no debería.
par
3
No funcionó para mí en el navegador como esperaba. Validated even reg.test ('3zzzzffe: 1900: 4545: 3: 200: f8ff: fe21: 67cf') que obviamente no es una dirección IPv6 válida. Obtuve
Capaj
7
fantástico ipv6 regex. Encontré un pequeño error con la sección de enlace local. tenías un lugar fe80donde debería ser algo como [fF][eE]80y un ffffque debería ser algo así[fF]{4}
user2831628
4
+1 para mostrar que las expresiones regulares pueden ser (de la misma manera que cualquier código fuente) realmente legibles si se cuida y formatea.
Natix
52

Lo siguiente validará las direcciones IPv4, IPv6 (completa y comprimida) e IPv6v4 (completa y comprimida):

'/^(?>(?>([a-f0-9]{1,4})(?>:(?1)){7}|(?!(?:.*[a-f0-9](?>:|$)){8,})((?1)(?>:(?1)){0,6})?::(?2)?)|(?>(?>(?1)(?>:(?1)){5}:|(?!(?:.*[a-f0-9]:){6,})(?3)?::(?>((?1)(?>:(?1)){0,4}):)?)?(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?>\.(?4)){3}))$/iD'
MichaelRushton
fuente
8
Aunque la validación de ip-s podría hacerse como sugiere Frank Krueger, esta solución es la que realmente responde a la pregunta (aunque todavía no la he probado completamente), así como si tiene muchas IP-s que desea probar sintácticamente y tal vez coincidir en una línea de texto, no puede utilizar la técnica de validación de IP.
Gyuri
Hola, probé esta expresión regular y no me funcionó. Dice que D es un indicador no válido y cuando lo elimino dice "SyntaxError: cuantificador inválido"
diosney
3
JavaScript implementa un subconjunto de expresiones regulares de estilo Perl, no la totalidad de PCRE. Mi expresión regular no funcionará sin algunas de las funciones avanzadas de PCRE.
MichaelRushton
2
Esto me da una excepción en C #
sarat
1
Caso de prueba fallido: FE80: 0000: 0000: 0000: 0202: B3FF: FE1E: 8329 Usando la última versión de Elixir en esta fecha, que usa PCRE debajo.
pmarreck
23

Parece que puede estar usando Python. Si es así, puede usar algo como esto:

import socket

def check_ipv6(n):
    try:
        socket.inet_pton(socket.AF_INET6, n)
        return True
    except socket.error:
        return False

print check_ipv6('::1') # True
print check_ipv6('foo') # False
print check_ipv6(5)     # TypeError exception
print check_ipv6(None)  # TypeError exception

No creo que tenga que tener IPv6 compilado en Python para obtener inet_pton, que también puede analizar direcciones IPv4 si pasa socket.AF_INETcomo el primer parámetro. Nota: es posible que esto no funcione en sistemas que no sean Unix.

Joe Hildebrand
fuente
4
Debe especificar el tipo de excepción en la exceptcláusula. De lo contrario, exceptdetectará todo y puede enmascarar errores no relacionados. El tipo aquí debería ser socket.error.
Ayman Hourieh
A) inet_pton no arroja otras excepciones, a menos que los documentos estén equivocados, y B) incluso si lo hiciera, ¿qué más devolvería sino False?
Joe Hildebrand
2
Re: otros errores ... si el usuario pasa en una no cadena, TypeError se come. Claramente, una lista no es un ipv6, pero probablemente me gustaría tener una carpa que estaba pasando en el tipo incorrecto.
Gregg Lind
1
+1 Esto me ayudó mucho. Se deben agregar un par de puntos adicionales: 1) socket.inet_pton se puede usar para probar la validez de ambas familias de direcciones IP (IP e IPv6). 2) Los documentos aquí ( docs.python.org/2/library/socket.html ) sugieren que esto está disponible en plataformas Unix. Es posible que no esté disponible en plataformas Win.
mkoistinen
usando django y esto ayuda!
elad silver
23

Desde " IPv6 regex ":

(\A([0-9a-f]{1,4}:){1,1}(:[0-9a-f]{1,4}){1,6}\Z)|
(\A([0-9a-f]{1,4}:){1,2}(:[0-9a-f]{1,4}){1,5}\Z)|
(\A([0-9a-f]{1,4}:){1,3}(:[0-9a-f]{1,4}){1,4}\Z)|
(\A([0-9a-f]{1,4}:){1,4}(:[0-9a-f]{1,4}){1,3}\Z)|
(\A([0-9a-f]{1,4}:){1,5}(:[0-9a-f]{1,4}){1,2}\Z)|
(\A([0-9a-f]{1,4}:){1,6}(:[0-9a-f]{1,4}){1,1}\Z)|
(\A(([0-9a-f]{1,4}:){1,7}|:):\Z)|
(\A:(:[0-9a-f]{1,4}){1,7}\Z)|
(\A((([0-9a-f]{1,4}:){6})(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3})\Z)|
(\A(([0-9a-f]{1,4}:){5}[0-9a-f]{1,4}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3})\Z)|
(\A([0-9a-f]{1,4}:){5}:[0-9a-f]{1,4}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\Z)|
(\A([0-9a-f]{1,4}:){1,1}(:[0-9a-f]{1,4}){1,4}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\Z)|
(\A([0-9a-f]{1,4}:){1,2}(:[0-9a-f]{1,4}){1,3}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\Z)|
(\A([0-9a-f]{1,4}:){1,3}(:[0-9a-f]{1,4}){1,2}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\Z)|
(\A([0-9a-f]{1,4}:){1,4}(:[0-9a-f]{1,4}){1,1}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\Z)|
(\A(([0-9a-f]{1,4}:){1,5}|:):(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\Z)|
(\A:(:[0-9a-f]{1,4}){1,5}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\Z)
Factor místico
fuente
45
Una expresión regular como esta debería ser un "olor a código" que quizás la expresión regular no sea la solución más adecuada aquí. (Aunque, supongo que la operación lo pidió ...)
Thanatos
10
@ user712092 - todos los que han visto una base de código con monstruosidades como esa
danielpops
2
Esta es una parodia completamente innecesaria para los RE. El programa que lo generó no entendió lo que estaba haciendo. Un humano nunca lo haría de esta manera. No se deje engañar por la aparente complejidad: los RE son de hecho "magia negra" para muchas personas, ¡pero no hay razón para colocarlos en otro planeta!
Chuck Kollars
+1, pero Dios mío, tiene que haber una mejor manera de hacer esto: P Para referencia: para Rails esto podría ayudar: stackoverflow.com/questions/16965697/…
Tilo
1
De hecho, es un olor a código; sin embargo, después de echar un vistazo, verá que cada expresión regular es bastante concisa. El problema es que hay diferentes patrones creados por la 'compresión' de ipv6: dos puntos al principio, en el medio y al final, además de que si ha usado los dos puntos dobles, no puede volver a usarlo, además del total los dos puntos antes y después del doble deben sumar. Perl 6 podría abordar esto, pero está mucho más allá de la sintaxis PCRE. (PD: no cuento el ipv4 integrado al final, ¡que es más largo que la sección ipv6!)
Gerard ONeill
11

Tendría que apoyar firmemente la respuesta de Frank Krueger .

Si bien dice que necesita una expresión regular para que coincida con una dirección IPv6, supongo que lo que realmente necesita es poder verificar si una cadena determinada es una dirección IPv6 válida. Aquí hay una distinción sutil pero importante.

Hay más de una forma de verificar si una cadena dada es una dirección IPv6 válida y la coincidencia de expresiones regulares es solo una solución.

Utilice una biblioteca existente si puede. La biblioteca tendrá menos errores y su uso resultará en menos código para mantener.

La expresión regular sugerida por Factor Mystic es larga y compleja. Lo más probable es que funcione, pero también debe considerar cómo se las arreglaría si fallara inesperadamente. El punto que trato de señalar aquí es que si no puede formar una expresión regular requerida usted mismo, no podrá depurarla fácilmente.

Si no tiene una biblioteca adecuada, puede ser mejor escribir su propia rutina de validación de IPv6 que no dependa de expresiones regulares. Si lo escribes lo entiendes y si lo entiendes puedes agregar comentarios para explicarlo para que otros también puedan entenderlo y posteriormente mantenerlo.

Actúe con precaución cuando utilice una expresión regular cuya funcionalidad no pueda explicar a otra persona.

Jon Cram
fuente
1
Usar dos expresiones regulares, una expresión liberal y una expresión de excepciones para atrapar direcciones no válidas permitidas por la primera, podría ser más fácil que una expresión ( return ex1.match(S) && ! ex2.match(S)).
Raedwald
4
Está asumiendo que está validando direcciones IP individuales cuando es casi seguro que busca direcciones IP en un gran bloque de texto.
Navin
8

No soy un experto en Ipv6, pero creo que puedes obtener un resultado bastante bueno más fácilmente con este:

^([0-9A-Fa-f]{0,4}:){2,7}([0-9A-Fa-f]{1,4}$|((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4})$

para responder "es un ipv6 válido", me parece que está bien. Para dividirlo en partes ... olvídalo. He omitido el no especificado (: :) ya que no sirve de nada tener una "dirección no especificada" en mi base de datos.

el principio: ^([0-9A-Fa-f]{0,4}:){2,7}<- coincide con la parte comprimible, podemos traducir esto como: entre 2 y 7 dos puntos que pueden tener un número hexadecimal entre ellos.

seguido de: [0-9A-Fa-f]{1,4}$<- un número hexadecimal (0 a la ((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4}izquierda omitido) O <- una dirección Ipv4

Remi Morin
fuente
1
+1 por ceñirse a la pregunta de los OP y presentar una expresión regular relativamente atractiva que de alguna manera funciona.
xebeche
1
Esto no coincide con ":: 1"
lsalamon
¿Eh? En el sintaxis java regex coincide:start() = 0, end() = 3 group(0) = "::1" group(1) = ":" group(2) = "1" group(3) = "null" group(4) = "null" group(5) = "null"
Remi Morin
En otro lugar, alguien me notifica de un problema con mi expresión regular, la parte comprimida "::" solo puede aparecer una vez. Entonces ":: 1 :: 2" coincidiría con mi expresión regular pero no es un IPV6 válido. Una segunda expresión regular puede validar este caso. La recomendación completa fue utilizar un analizador con estado para validar. Estoy de acuerdo en que el código resultante será más fácil de leer y mantener (y probablemente alguien ya lo codificó en un código abierto en alguna parte).
Remi Morin
8

Esto también detecta el loopback (:: 1) y las direcciones ipv6. cambió {} a + y puso: dentro del primer corchete.

([a-f0-9:]+:+)+[a-f0-9]+

probado con ifconfig -a salida http://regexr.com/

La opción o terminal de Unix o Mac OSx devuelve solo la salida coincidente (ipv6) que incluye :: 1

ifconfig -a | egrep -o '([a-f0-9:]+:+)+[a-f0-9]+'

Obtenga todas las direcciones IP (IPv4 o IPv6) e imprima la coincidencia en un término de Unix OSx

ifconfig -a | egrep -o '([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}) | (([a-f0-9:]+:+)+[a-f0-9]+)'
Rohit Malgaonkar
fuente
Me gusta la sencillez. Esto finalmente funcionó para mí:ip a | grep -Po '[\w:]+:+[\w:]+'
Noam Manos
¡Se agradece el humor!
Soumya Kanti
Cuando ejecuto ipconfig / all, mi dirección IP termina con% 10, ¿esta expresión no coincide con esta parte?
Peter
7

Esta expresión regular coincidirá con las direcciones IPv6 e IPv4 válidas de acuerdo con la implementación GNU C ++ de expresiones regulares con el modo REGULAR EXTENDED utilizado:

"^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}))|:)))(%.+)?\s*$"
janCafé
fuente
5

¡Tener cuidado! En Java, el uso de InetAddress y clases relacionadas (Inet4Address, Inet6Address, URL) puede involucrar tráfico de red. Por ejemplo, resolución de DNS (URL.equals, InetAddress de la cadena). ¡Esta llamada puede tardar mucho y se está bloqueando!

Para IPv6 tengo algo como esto. Por supuesto, esto no maneja los detalles muy sutiles de IPv6 como que los índices de zona están permitidos solo en algunas clases de direcciones IPv6. Y esta expresión regular no está escrita para la captura de grupos, es solo un tipo de expresión regular de "coincidencias".

S - Segmento IPv6 = [0-9a-f]{1,4}

I - IPv4 = (?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9]{1,2})\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9]{1,2})

Esquema (la primera parte coincide con las direcciones IPv6 con el sufijo IPv4, la segunda parte coincide con las direcciones IPv6, la última parte es el índice de la zona):

(
(
::(S:){0,5}|
S::(S:){0,4}|
(S:){2}:(S:){0,3}|
(S:){3}:(S:){0,2}|
(S:){4}:(S:)?|
(S:){5}:|
(S:){6}
)
I

|

:(:|(:S){1,7})|
S:(:|(:S){1,6})|
(S:){2}(:|(:S){1,5})|
(S:){3}(:|(:S){1,4})|
(S:){4}(:|(:S){1,3})|
(S:){5}(:|(:S){1,2})|
(S:){6}(:|(:S))|
(S:){7}:|
(S:){7}S
)

(?:%[0-9a-z]+)?

Y aquí la expresión regular might (no distingue entre mayúsculas y minúsculas, rodee con lo que sea necesario como principio / final de línea, etc.):

(?:
(?:
::(?:[0-9a-f]{1,4}:){0,5}|
[0-9a-f]{1,4}::(?:[0-9a-f]{1,4}:){0,4}|
(?:[0-9a-f]{1,4}:){2}:(?:[0-9a-f]{1,4}:){0,3}|
(?:[0-9a-f]{1,4}:){3}:(?:[0-9a-f]{1,4}:){0,2}|
(?:[0-9a-f]{1,4}:){4}:(?:[0-9a-f]{1,4}:)?|
(?:[0-9a-f]{1,4}:){5}:|
(?:[0-9a-f]{1,4}:){6}
)
(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9]{1,2})\.){3}
(?:25[0-5]|2[0-4][0-9]|[01]?[0-9]{1,2})|

:(?::|(?::[0-9a-f]{1,4}){1,7})|
[0-9a-f]{1,4}:(?::|(?::[0-9a-f]{1,4}){1,6})|
(?:[0-9a-f]{1,4}:){2}(?::|(?::[0-9a-f]{1,4}){1,5})|
(?:[0-9a-f]{1,4}:){3}(?::|(?::[0-9a-f]{1,4}){1,4})|
(?:[0-9a-f]{1,4}:){4}(?::|(?::[0-9a-f]{1,4}){1,3})|
(?:[0-9a-f]{1,4}:){5}(?::|(?::[0-9a-f]{1,4}){1,2})|
(?:[0-9a-f]{1,4}:){6}(?::|(?::[0-9a-f]{1,4}))|
(?:[0-9a-f]{1,4}:){7}:|
(?:[0-9a-f]{1,4}:){7}[0-9a-f]{1,4}
)

(?:%[0-9a-z]+)?
usuario2623580
fuente
4

La siguiente expresión regular es solo para IPv6. El grupo 1 coincide con la IP.

(([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4})
Jitendra Gosavi
fuente
+1 No siempre es necesario tener una expresión regular súper compleja perfecta que un humano no pueda entender. Usaré este porque entiendo lo que hace y, en mi caso, puedo estar seguro de que si tengo algo que se parezca a un ipv6 válido, entonces es un ipv6 válido.
David L.
3
esto no coincidiría con: fe80 :: 1 o 2342: 32fd :: 2d32
James
3

Una expresión regular simple que coincidirá, pero no recomendaría para la validación de ningún tipo es esta:

([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4}

Tenga en cuenta que esto coincide con la compresión en cualquier lugar de la dirección, aunque no coincidirá con la dirección de loopback :: 1. Considero que esto es un compromiso razonable para mantener la expresión regular simple.

Utilizo con éxito esto en las reglas de selección inteligente iTerm2 para hacer cuatro clics en direcciones IPv6.

JinnKo
fuente
3
¡Querías decir que A-Fno A-Z! También tenga en cuenta que está excluyendo la notación de cuatro puntos.
xebeche
2

En Scala use los conocidos validadores de Apache Commons.

http://mvnrepository.com/artifact/commons-validator/commons-validator/1.4.1

libraryDependencies += "commons-validator" % "commons-validator" % "1.4.1"


import org.apache.commons.validator.routines._

/**
 * Validates if the passed ip is a valid IPv4 or IPv6 address.
 *
 * @param ip The IP address to validate.
 * @return True if the passed IP address is valid, false otherwise.
 */  
 def ip(ip: String) = InetAddressValidator.getInstance().isValid(ip)

Siguiendo las pruebas del método ip(ip: String):

"The `ip` validator" should {
  "return false if the IPv4 is invalid" in {
    ip("123") must beFalse
    ip("255.255.255.256") must beFalse
    ip("127.1") must beFalse
    ip("30.168.1.255.1") must beFalse
    ip("-1.2.3.4") must beFalse
  }

  "return true if the IPv4 is valid" in {
    ip("255.255.255.255") must beTrue
    ip("127.0.0.1") must beTrue
    ip("0.0.0.0") must beTrue
  }

  //IPv6
  //@see: http://www.ronnutter.com/ipv6-cheatsheet-on-identifying-valid-ipv6-addresses/
  "return false if the IPv6 is invalid" in {
    ip("1200::AB00:1234::2552:7777:1313") must beFalse
  }

  "return true if the IPv6 is valid" in {
    ip("1200:0000:AB00:1234:0000:2552:7777:1313") must beTrue
    ip("21DA:D3:0:2F3B:2AA:FF:FE28:9C5A") must beTrue
  }
}
OliverKK
fuente
Interesante, afirma comprobar que es una dirección válida, " Valida si la ip pasada es una dirección IPv4 o IPv6 válida ", pero en realidad solo comprueba que esté formateada como una dirección válida. Por ejemplo, 1200:0000:AB00:1234:0000:2552:7777:1313es un formato válido para una dirección IPv6, pero no es una dirección IPv6 válida como devuelve el método de prueba. Apuesto a que cree que 241.54.113.65es una dirección IPv4 válida.
Ron Maupin
2

Al observar los patrones incluidos en las otras respuestas, hay una serie de buenos patrones que se pueden mejorar haciendo referencia a grupos y utilizando búsquedas anticipadas. Aquí hay un ejemplo de un patrón que hace referencia a sí mismo que utilizaría en PHP si tuviera que hacerlo:

^(?<hgroup>(?<hex>[[:xdigit:]]{0,4}) # grab a sequence of up to 4 hex digits
                                     # and name this pattern for usage later
     (?<!:::):{1,2})                 # match 1 or 2 ':' characters
                                     # as long as we can't match 3
 (?&hgroup){1,6} # match our hex group 1 to 6 more times
 (?:(?:
    # match an ipv4 address or
    (?<dgroup>2[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3}(?&dgroup)
    # match our hex group one last time
    |(?&hex))$

Nota: PHP tiene un filtro incorporado para esto, que sería una mejor solución que este patrón.

Análisis Regex101

Steve Buzonas
fuente
2

Genere lo siguiente usando python y funciona con el módulo re. Las afirmaciones de anticipación garantizan que aparezca el número correcto de puntos o dos puntos en la dirección. No es compatible con IPv4 en notación IPv6.

pattern = '^(?=\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$)(?:(?:25[0-5]|[12][0-4][0-9]|1[5-9][0-9]|[1-9]?[0-9])\.?){4}$|(?=^(?:[0-9a-f]{0,4}:){2,7}[0-9a-f]{0,4}$)(?![^:]*::.+::[^:]*$)(?:(?=.*::.*)|(?=\w+:\w+:\w+:\w+:\w+:\w+:\w+:\w+))(?:(?:^|:)(?:[0-9a-f]{4}|[1-9a-f][0-9a-f]{0,3})){0,8}(?:::(?:[0-9a-f]{1,4}(?:$|:)){0,6})?$'
result = re.match(pattern, ip)
if result: result.group(0)
Mike Wilmes
fuente
2

Las expresiones regulares para ipv6 pueden ser realmente complicadas cuando se consideran direcciones con ipv4 incrustado y direcciones que están comprimidas, como puede ver en algunas de estas respuestas.

La biblioteca Java IPAddress de código abierto validará todas las representaciones estándar de IPv6 e IPv4 y también admite la longitud del prefijo (y la validación de las mismas). Descargo de responsabilidad: soy el gerente de proyecto de esa biblioteca.

Ejemplo de código:

        try {
            IPAddressString str = new IPAddressString("::1");
            IPAddress addr = str.toAddress();
            if(addr.isIPv6() || addr.isIPv6Convertible()) {
                IPv6Address ipv6Addr = addr.toIPv6();
            }
            //use address
        } catch(AddressStringException e) {
            //e.getMessage has validation error
        }
Sean F
fuente
1

En Java, puede usar la clase de biblioteca sun.net.util.IPAddressUtil:

IPAddressUtil.isIPv6LiteralAddress(iPaddress);
user463639
fuente
3
sun.net. * es una API privada.
David Kocher
1

Es difícil encontrar una expresión regular que funcione para todos los casos de IPv6. Por lo general, son difíciles de mantener, no son fáciles de leer y pueden causar problemas de rendimiento. Por lo tanto, quiero compartir una solución alternativa que he desarrollado: Expresión regular (RegEx) para IPv6 separada de IPv4

Ahora puede preguntar: "Este método solo encuentra IPv6, ¿cómo puedo encontrar IPv6 en un texto o archivo?" Aquí también hay métodos para este problema.

Nota : Si no desea utilizar la clase IPAddress en .NET, también puede reemplazarla con mi método . También cubre IPv4 mapeado y casos especiales, mientras que IPAddress no cubre.

class IPv6
{
    public List<string> FindIPv6InFile(string filePath)
    {
        Char ch;
        StringBuilder sbIPv6 = new StringBuilder();
        List<string> listIPv6 = new List<string>();
        StreamReader reader = new StreamReader(filePath);
        do
        {
            bool hasColon = false;
            int length = 0;

            do
            {
                ch = (char)reader.Read();

                if (IsEscapeChar(ch))
                    break;

                //Check the first 5 chars, if it has colon, then continue appending to stringbuilder
                if (!hasColon && length < 5)
                {
                    if (ch == ':')
                    {
                        hasColon = true;
                    }
                    sbIPv6.Append(ch.ToString());
                }
                else if (hasColon) //if no colon in first 5 chars, then dont append to stringbuilder
                {
                    sbIPv6.Append(ch.ToString());
                }

                length++;

            } while (!reader.EndOfStream);

            if (hasColon && !listIPv6.Contains(sbIPv6.ToString()) && IsIPv6(sbIPv6.ToString()))
            {
                listIPv6.Add(sbIPv6.ToString());
            }

            sbIPv6.Clear();

        } while (!reader.EndOfStream);
        reader.Close();
        reader.Dispose();

        return listIPv6;
    }

    public List<string> FindIPv6InText(string text)
    {
        StringBuilder sbIPv6 = new StringBuilder();
        List<string> listIPv6 = new List<string>();

        for (int i = 0; i < text.Length; i++)
        {
            bool hasColon = false;
            int length = 0;

            do
            {
                if (IsEscapeChar(text[length + i]))
                    break;

                //Check the first 5 chars, if it has colon, then continue appending to stringbuilder
                if (!hasColon && length < 5)
                {
                    if (text[length + i] == ':')
                    {
                        hasColon = true;
                    }
                    sbIPv6.Append(text[length + i].ToString());
                }
                else if (hasColon) //if no colon in first 5 chars, then dont append to stringbuilder
                {
                    sbIPv6.Append(text[length + i].ToString());
                }

                length++;

            } while (i + length != text.Length);

            if (hasColon && !listIPv6.Contains(sbIPv6.ToString()) && IsIPv6(sbIPv6.ToString()))
            {
                listIPv6.Add(sbIPv6.ToString());
            }

            i += length;
            sbIPv6.Clear();
        }

        return listIPv6;
    }

    bool IsEscapeChar(char ch)
    {
        if (ch != ' ' && ch != '\r' && ch != '\n' && ch!='\t')
        {
            return false;
        }

        return true;
    }

    bool IsIPv6(string maybeIPv6)
    {
        IPAddress ip;
        if (IPAddress.TryParse(maybeIPv6, out ip))
        {
            return ip.AddressFamily == AddressFamily.InterNetworkV6;
        }
        else
        {
            return false;
        }
    }

}
Nuh Metin Güler
fuente
1

InetAddressUtilstiene todos los patrones definidos. Terminé usando su patrón directamente y lo pego aquí como referencia:

private static final String IPV4_BASIC_PATTERN_STRING =
        "(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}" + // initial 3 fields, 0-255 followed by .
         "([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])"; // final field, 0-255

private static final Pattern IPV4_PATTERN =
    Pattern.compile("^" + IPV4_BASIC_PATTERN_STRING + "$");

private static final Pattern IPV4_MAPPED_IPV6_PATTERN = // TODO does not allow for redundant leading zeros
        Pattern.compile("^::[fF]{4}:" + IPV4_BASIC_PATTERN_STRING + "$");

private static final Pattern IPV6_STD_PATTERN =
    Pattern.compile(
            "^[0-9a-fA-F]{1,4}(:[0-9a-fA-F]{1,4}){7}$");

private static final Pattern IPV6_HEX_COMPRESSED_PATTERN =
    Pattern.compile(
            "^(([0-9A-Fa-f]{1,4}(:[0-9A-Fa-f]{1,4}){0,5})?)" + // 0-6 hex fields
             "::" +
             "(([0-9A-Fa-f]{1,4}(:[0-9A-Fa-f]{1,4}){0,5})?)$"); // 0-6 hex fields 
usuario4604205
fuente
1

¿Estás usando Ruby? Prueba esto:

/^(((?=.*(::))(?!.*\3.+\3))\3?|[\dA-F]{1,4}:)([\dA-F]{1,4}(\3|:\b)|\2){5}(([\dA-F]{1,4}(\3|:\b|$)|\2){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4})\z/i
Ahamx
fuente
1

Según sus necesidades, una aproximación como:

[0-9a-f:]+

puede ser suficiente (como con grepping simple de archivos de registro, por ejemplo).

Bill Lipa
fuente
0

Para usuarios de PHP 5.2+ filter_varfunciona muy bien.

Sé que esto no responde a la pregunta original (específicamente una solución de expresiones regulares), pero publico esto con la esperanza de que pueda ayudar a alguien más en el futuro.

$is_ip4address = (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== FALSE);
$is_ip6address = (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) !== FALSE);
Alambre azul
fuente
0

Esto funcionará para IPv4 e IPv6:

^(([0-9a-f]{0,4}:){1,7}[0-9a-f]{1,4}|([0-9]{1,3}\.){3}[0-9]{1,3})$
Chris
fuente
2
Coincide con direcciones no válidas con 2 instancias de ::. por ejemplo2404:6800::4003:c02::8a
nhahtdh
coincide con IPv4 no válido 666.666.666.666
Ryan Williams
0

Esto es lo que se me ocurrió, usando un poco de anticipación y grupos con nombre. Por supuesto, esto es solo IPv6, pero no debería interferir con patrones adicionales si desea agregar IPv4:

(?=([0-9a-f]+(:[0-9a-f])*)?(?P<wild>::)(?!([0-9a-f]+:)*:))(::)?([0-9a-f]{1,4}:{1,2}){0,6}(?(wild)[0-9a-f]{0,4}|[0-9a-f]{1,4}:[0-9a-f]{1,4})
user1977022
fuente
0

Puede utilizar las herramientas de shell ipextract que hice para este propósito. Están basados ​​en regexp y grep.

Uso:

$ ifconfig | ipextract6
fe80::1%lo0
::1
fe80::7ed1:c3ff:feec:dee1%en0
Phil L.
fuente
0

Simplemente haciendo coincidir los locales de un origen con corchetes incluidos. Sé que no es tan completo, pero en javascript los otros tenían problemas para rastrear principalmente el de no funcionar, por lo que parece que esto me da lo que necesitaba por ahora. Tampoco se necesitan AF mayúsculas adicionales.

^\[([0-9a-fA-F]{1,4})(\:{1,2})([0-9a-fA-F]{1,4})(\:{1,2})([0-9a-fA-F]{1,4})(\:{1,2})([0-9a-fA-F]{1,4})(\:{1,2})([0-9a-fA-F]{1,4})\]

La versión de Jinnko está simplificada y veo mejor.

Maestro James
fuente
0

Como se indicó anteriormente, otra forma de obtener un analizador de validación de representación textual IPv6 es mediante programación. Aquí hay uno que es totalmente compatible con RFC-4291 y RFC-5952. Escribí este código en ANSI C (funciona con GCC, pasé las pruebas en Linux, funciona con clang, pasé las pruebas en FreeBSD). Por lo tanto, solo se basa en la biblioteca estándar ANSI C, por lo que se puede compilar en todas partes (lo he usado para analizar IPv6 dentro de un módulo del kernel con FreeBSD).

// IPv6 textual representation validating parser fully compliant with RFC-4291 and RFC-5952
// BSD-licensed / Copyright 2015-2017 Alexandre Fenyo

#include <string.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>

typedef enum { false, true } bool;

static const char hexdigits[] = "0123456789abcdef";
static int digit2int(const char digit) {
  return strchr(hexdigits, digit) - hexdigits;
}

// This IPv6 address parser handles any valid textual representation according to RFC-4291 and RFC-5952.
// Other representations will return -1.
//
// note that str input parameter has been modified when the function call returns
//
// parse_ipv6(char *str, struct in6_addr *retaddr)
// parse textual representation of IPv6 addresses
// str:     input arg
// retaddr: output arg
int parse_ipv6(char *str, struct in6_addr *retaddr) {
  bool compressed_field_found = false;
  unsigned char *_retaddr = (unsigned char *) retaddr;
  char *_str = str;
  char *delim;

  bzero((void *) retaddr, sizeof(struct in6_addr));
  if (!strlen(str) || strchr(str, ':') == NULL || (str[0] == ':' && str[1] != ':') ||
      (strlen(str) >= 2 && str[strlen(str) - 1] == ':' && str[strlen(str) - 2] != ':')) return -1;

  // convert transitional to standard textual representation
  if (strchr(str, '.')) {
    int ipv4bytes[4];
    char *curp = strrchr(str, ':');
    if (curp == NULL) return -1;
    char *_curp = ++curp;
    int i;
    for (i = 0; i < 4; i++) {
      char *nextsep = strchr(_curp, '.');
      if (_curp[0] == '0' || (i < 3 && nextsep == NULL) || (i == 3 && nextsep != NULL)) return -1;
      if (nextsep != NULL) *nextsep = 0;
      int j;
      for (j = 0; j < strlen(_curp); j++) if (_curp[j] < '0' || _curp[j] > '9') return -1;
      if (strlen(_curp) > 3) return -1;
      const long val = strtol(_curp, NULL, 10);
      if (val < 0 || val > 255) return -1;
      ipv4bytes[i] = val;
      _curp = nextsep + 1;
    }
    sprintf(curp, "%x%02x:%x%02x", ipv4bytes[0], ipv4bytes[1], ipv4bytes[2], ipv4bytes[3]);
  }

  // parse standard textual representation
  do {
    if ((delim = strchr(_str, ':')) == _str || (delim == NULL && !strlen(_str))) {
      if (delim == str) _str++;
      else if (delim == NULL) return 0;
      else {
        if (compressed_field_found == true) return -1;
        if (delim == str + strlen(str) - 1 && _retaddr != (unsigned char *) (retaddr + 1)) return 0;
        compressed_field_found = true;
        _str++;
        int cnt = 0;
        char *__str;
        for (__str = _str; *__str; ) if (*(__str++) == ':') cnt++;
        unsigned char *__retaddr = - 2 * ++cnt + (unsigned char *) (retaddr + 1);
        if (__retaddr <= _retaddr) return -1;
        _retaddr = __retaddr;
      }
    } else {
      char hexnum[4] = "0000";
      if (delim == NULL) delim = str + strlen(str);
      if (delim - _str > 4) return -1;
      int i;
      for (i = 0; i < delim - _str; i++)
        if (!isxdigit(_str[i])) return -1;
        else hexnum[4 - (delim - _str) + i] = tolower(_str[i]);
      _str = delim + 1;
      *(_retaddr++) = (digit2int(hexnum[0]) << 4) + digit2int(hexnum[1]);
      *(_retaddr++) = (digit2int(hexnum[2]) << 4) + digit2int(hexnum[3]);
    }
  } while (_str < str + strlen(str));
  return 0;
}
Alexandre Fenyo
fuente
-1

Prueba este pequeño de una sola línea. Solo debe coincidir con direcciones IPv6 comprimidas / sin comprimir válidas (no híbridos IPv4)

/(?!.*::.*::)(?!.*:::.*)(?!:[a-f0-9])((([a-f0-9]{1,4})?[:](?!:)){7}|(?=(.*:[:a-f0-9]{1,4}::|^([:a-f0-9]{1,4})?::))(([a-f0-9]{1,4})?[:]{1,2}){1,6})[a-f0-9]{1,4}/
Carlos Velázquez
fuente
En realidad, las direcciones IPv6 válidas incluyen sin comprimir, comprimidas, híbridas sin comprimir e híbridas comprimidas. Realmente se necesita mucho más de lo que tiene para hacer coincidir cualquier representación de texto válida de una dirección IPv6.
Ron Maupin
-2

La expresión regular permite el uso de ceros a la izquierda en las partes de IPv4.

Algunas distribuciones de Unix y Mac convierten esos segmentos en octales.

Sugiero usarlo 25[0-5]|2[0-4]\d|1\d\d|[1-9]?\dcomo segmento IPv4.

Aeron
fuente
-2

Si solo desea IP-s normales (sin barras), aquí:

^(?:[0-9a-f]{1,4}(?:::)?){0,7}::[0-9a-f]+$

Lo uso para mi marcador de sintaxis en la aplicación de edición de archivos de hosts. Funciona como encanto.

Harry
fuente
No hay manera de que esto funcione decentemente, no puede coincidir con una sola dirección ipv6 con dos puntos, todas sus coincidencias están en dos puntos dobles y explícitamente requiere dos puntos dobles para su último grupo, el resumen puede ocurrir en cualquier lugar. .
KillianDS
(?: [0-9a-f] {1,4} (? :::?)?) {0,7} ::? [0-9a-f] {1,4}
Harry
Aún está mal, pero incluso entonces terminará repitiendo la respuesta de JinnKo, que es lo suficientemente buena para propósitos simples, pero aún tiene fallas (no detecta doble resumen y no permite quads punteados, ni localhost, ni :: terminación,. ..)
KillianDS