Expressão regular que corresponde a endereços IPv6 válidos


111

Estou tendo problemas para escrever uma expressão regular que corresponda a endereços IPv6 válidos, incluindo aqueles em sua forma compactada (com ::ou zeros à esquerda omitidos de cada par de bytes).

Alguém pode sugerir uma expressão regular que cumpra o requisito?

Estou pensando em expandir cada par de bytes e combinar o resultado com um regex mais simples.


1
Verifique intermapper.com/ipv6validator .. ele tem um link para este script de teste perl
Mottie

Tentei todas as respostas abaixo e elas não funcionam para todos os meus casos de teste e / ou também incluem IPv4 que não foi solicitado. Achei que esta é a solução mais limpa até agora: stackoverflow.com/a/21944928/3112803
gfrobenius

Respostas:


252

Não consegui que a resposta de @Factor Mystic funcionasse com expressões regulares POSIX, então escrevi uma que funciona com expressões regulares POSIX e expressões regulares PERL.

Deve corresponder a:

Expressão regular 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 a leitura, o seguinte é a expressão regular acima dividida em pontos OR principais em linhas 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 a compreensão do acima, o seguinte código "pseudo" replica o acima:

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)
           )

Eu postei um script no GitHub que testa a expressão regular: https://gist.github.com/syzdek/6086792


3
Seu IPv4 regex não corresponde a IPs como127.000.000.001
Kentzo

21
Os segmentos IPv4 não devem incluir zeros à esquerda. Se um zero à esquerda estiver presente, o segmento IPv4 deve ser interpretado em octal. Portanto, o IPV4SEG acima está correto em não permitir '000'. No entanto, permite '00', o que não deveria.
par

3
Não funcionou para mim no navegador como eu esperava. Validado até mesmo reg.test ('3zzzzffe: 1900: 4545: 3: 200: f8ff: fe21: 67cf') que obviamente não é um endereço IPv6 válido. Teve resultados muito melhores com regex aqui: nbviewer.ipython.org/github/rasbt/python_reference/blob/master/…
Capaj 08/02/2015

7
fantástico regex ipv6. encontrou um pequeno bug com a seção local do link. você tinha fe80onde deveria ser algo [fF][eE]80e um ffffque deveria ser algo como[fF]{4}
user2831628

4
+1 para mostrar que os regexes podem ser (da mesma maneira que qualquer código-fonte) realmente legíveis se você tomar cuidado e formatá-los.
Natix

52

O seguinte irá validar os endereços IPv4, IPv6 (completo e compactado) e IPv6v4 (completo e compactado):

'/^(?>(?>([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'

8
Mesmo que a validação de ip-s possa ser feita como sugere Frank Krueger, esta solução é a que realmente responde à pergunta (embora eu não tenha testado totalmente ainda), bem como se você tiver muitos IP-s que deseja testar sintaticamente e talvez corresponda em uma linha de texto, você não pode usar a técnica de validação de IP.
Gyuri

Olá, eu testei este RegExp e não funcionou para mim. Ele diz que D é um sinalizador inválido e quando eu o removo, ele diz "SyntaxError: quantificador inválido"
diosney

3
JavaScript implementa um subconjunto de expressões regulares de estilo Perl, não a totalidade de PCRE. Meu regex não funcionará sem alguns dos recursos avançados do PCRE.
MichaelRushton

2
Isso abre uma exceção para mim em C #
sarat

1
Caso de teste com falha: FE80: 0000: 0000: 0000: 0202: B3FF: FE1E: 8329 Usando a versão mais recente do Elixir nesta data, que usa PCRE por baixo.
pmarreck de

23

Parece que você está usando Python. Nesse caso, você pode usar algo assim:

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

Não acho que você precise ter IPv6 compilado em Python para obter inet_pton, que também pode analisar endereços IPv4 se você passar socket.AF_INETcomo o primeiro parâmetro. Nota: isso pode não funcionar em sistemas não-Unix.


4
Você deve especificar o tipo de exceção na exceptcláusula. Caso contrário, exceptirá capturar tudo e pode mascarar erros não relacionados. O tipo aqui deve ser socket.error.
Ayman Hourieh de

A) inet_pton não lança outras exceções, a menos que os documentos estejam errados, e B) mesmo se fizesse, o que mais você retornaria senão False?
Joe Hildebrand

2
Re: outros erros ... se o usuário passa em uma não string, TypeError é comido. É claro que uma lista não é um ipv6, mas provavelmente gostaria que ela me acusasse de estar passando no tipo errado.
Gregg Lind

1
+1 Isso me ajudou muito. Alguns pontos adicionais que devem ser adicionados: 1) socket.inet_pton pode ser usado para testar a validade de ambas as famílias de endereços IP (IP e IPv6). 2) Os documentos aqui ( docs.python.org/2/library/socket.html ) sugerem que isso está disponível em plataformas Unix. Pode não estar disponível em plataformas Win.
mkoistinen

usando django e isso ajuda!
elad silver

23

De " 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)

45
Expressões regulares como essa devem ser um "cheiro de código" que talvez expressões regulares não sejam a solução mais adequada aqui. (Embora, eu acho que a operação pediu por isso ...)
Thanatos

10
@ user712092 - todos que viram uma base de código com monstruosidades como essa
danielpops

2
Esta é uma farsa completamente desnecessária para REs. O programa que o gerou não entendeu o que estava fazendo. Um humano nunca faria isso dessa maneira. Não se deixe enganar pela aparente complexidade - REs são de fato "magia negra" para muitas pessoas, mas não há razão para colocá-los em outro planeta!
Chuck Kollars

+1 mas OMG, tem que haver uma maneira melhor de fazer isso: P Para referência: para Rails isso pode ajudar: stackoverflow.com/questions/16965697/…
Tilo

1
Na verdade, é um cheiro de código; entretanto, depois de dar uma olhada, você verá que cada regex é bastante concisa. O problema é que existem diferentes padrões criados pela 'compressão' de ipv6 - dois pontos no início, meio e fim, além de se você usou seus dois pontos duplos, você não pode usá-lo novamente, no topo do total dois pontos antes e depois do dobro devem somar. Perl 6 pode ser capaz de lidar com isso, mas está muito além da sintaxe PCRE. (PS - Não conto o ipv4 incorporado no final, que é mais longo do que a seção ipv6!)
Gerard ONeill

11

Eu teria que apoiar fortemente a resposta de Frank Krueger .

Embora você diga que precisa de uma expressão regular para corresponder a um endereço IPv6, estou assumindo que o que você realmente precisa é ser capaz de verificar se uma determinada string é um endereço IPv6 válido. Há uma distinção sutil, mas importante aqui.

Há mais de uma maneira de verificar se uma determinada string é um endereço IPv6 válido e a correspondência de expressão regular é apenas uma solução.

Use uma biblioteca existente, se puder. A biblioteca terá menos bugs e seu uso resultará em menos código para você manter.

A expressão regular sugerida pelo Factor Mystic é longa e complexa. Provavelmente funciona, mas você também deve considerar como lidaria se ele falhasse inesperadamente. O que estou tentando enfatizar aqui é que, se você não puder formar uma expressão regular exigida, não será capaz de depurá-la facilmente.

Se você não tiver uma biblioteca adequada, pode ser melhor escrever sua própria rotina de validação IPv6 que não dependa de expressões regulares. Se você o escrever, você o compreenderá e, se compreender, poderá adicionar comentários para explicá-lo, de modo que outros também possam entendê-lo e, posteriormente, mantê-lo.

Aja com cuidado ao usar uma expressão regular cuja funcionalidade você não pode explicar a outra pessoa.


1
Usar duas expressões regulares, uma expressão liberal e uma expressão de exceção para capturar endereços inválidos permitidos pela primeira, pode ser mais fácil do que uma expressão ( return ex1.match(S) && ! ex2.match(S)).
Raedwald,

4
Você está presumindo que ele está validando IPs individuais quando quase certamente está procurando por IPs em um grande bloco de texto.
Navin

8

Não sou um especialista em IPv6, mas acho que você pode obter um resultado muito bom mais facilmente com 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 "é um ipv6 válido" parece ok para mim. Para quebrar em partes ... esqueça. Omiti o não especificado (: :), uma vez que não adianta ter "endereço não especificado" em meu banco de dados.

o início: ^([0-9A-Fa-f]{0,4}:){2,7}<- corresponde à parte compressível, podemos traduzir isso como: entre 2 e 7 dois pontos que podem ter um número heaxadecimal entre eles.

seguido por: [0-9A-Fa-f]{1,4}$<- um número hexadecimal (0 inicial omitido) OU ((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4}<- um endereço Ipv4


1
+1 por realmente se ater à questão dos OPs e apresentar um regex relativamente bonito que funciona de alguma forma.
xebeche

1
Isso não corresponde a ":: 1"
lsalamon

Hã? Na sintaxe java regex, ele corresponde a:start() = 0, end() = 3 group(0) = "::1" group(1) = ":" group(2) = "1" group(3) = "null" group(4) = "null" group(5) = "null"
Remi Morin

Em algum outro lugar, alguém me notificou de um problema com minha regex, a parte compactada "::" só pode aparecer uma vez. Portanto, ":: 1 :: 2" corresponderia ao meu regex, mas não é um IPV6 válido. Uma segunda regex pode validar esse caso. A recomendação completa era usar um analisador com estado para validar. Concordo que o código resultante será mais fácil de ler e manter (e provavelmente alguém já o codificou em um código aberto em algum lugar).
Remi Morin,

8

Isso captura o loopback (:: 1) também e os endereços ipv6. mudou {} para + e colocou: dentro do primeiro colchete.

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

testado com ifconfig -a output http://regexr.com/

A opção o terminal Unix ou Mac OSx retorna apenas a saída correspondente (ipv6) incluindo :: 1

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

Obtenha todos os endereços IP (IPv4 OU IPv6) e imprima a correspondência no termo 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]+)'

Gosto da simplicidade. Isso acabou funcionando para mim:ip a | grep -Po '[\w:]+:+[\w:]+'
Noam Manos

Humor apreciado!
Soumya Kanti

Quando executo ipconfig / all, meu endereço IP termina com% 10, esta expressão não corresponde a esta parte?
Pedro

7

Esta expressão regular corresponderá a endereços IPv6 e IPv4 válidos de acordo com a implementação GNU C ++ de regex com o modo REGULAR EXTENDED usado:

"^\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*$"

5

Cuidado! Em Java, o uso de InetAddress e classes relacionadas (Inet4Address, Inet6Address, URL) pode envolver tráfego de rede! Por exemplo, resolução de DNS (URL.equals, InetAddress da string!). Esta chamada pode demorar e está bloqueando!

Para IPv6, tenho algo assim. É claro que isso não lida com os detalhes muito sutis do IPv6, como os índices de zona são permitidos apenas em algumas classes de endereços IPv6. E este regex não foi escrito para captura de grupo, é apenas um tipo de regexp que "combina".

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 (a primeira parte corresponde aos endereços IPv6 com o sufixo IPv4, a segunda parte corresponde aos endereços IPv6, último patrão do índice da 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]+)?

E aqui o pode regex (não diferencia maiúsculas de minúsculas, envolve o que for necessário, como início / fim de linha, 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]+)?

4

O regex a seguir é apenas para IPv6. O grupo 1 corresponde ao IP.

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

+1 Nem sempre é necessário ter uma regex supercomplexa perfeita que um humano não possa entender. Vou usar este porque entendo o que ele faz e, no meu caso, posso ter certeza que se recebi algo que se assemelha a um ipv6 válido, é um ipv6 válido.
David L.

3
isso não corresponderia a dizer: fe80 :: 1 ou 2342: 32fd :: 2d32
James

3

Um regex simples que corresponderá, mas eu não recomendaria para validação de qualquer tipo é este:

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

Observe que isso corresponde à compressão em qualquer lugar do endereço, embora não corresponda ao endereço de loopback :: 1. Acho este um meio-termo razoável para manter a regex simples.

Eu uso isso com sucesso nas regras de seleção inteligente de iTerm2 para endereços IPv6 de quatro cliques.


3
Você quis dizer A-F, não A-Z! Observe também que você está excluindo a notação com quatro pontos.
xebeche


2

No Scala, use os conhecidos validadores 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)

Seguindo os testes do 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
  }
}

Interessante, ele afirma verificar se é um endereço válido, " Valida se o ip passado é um endereço IPv4 ou IPv6 válido. ", Mas na verdade só verifica se está formatado como um endereço válido. Por exemplo, 1200:0000:AB00:1234:0000:2552:7777:1313é um formato válido para um endereço IPv6, mas não é um endereço IPv6 válido conforme o método de teste retorna. Aposto que ele pensa que 241.54.113.65é um endereço IPv4 válido.
Ron Maupin

2

Olhando para os padrões incluídos nas outras respostas, há uma série de bons padrões que podem ser melhorados referenciando grupos e utilizando antecipações. Aqui está um exemplo de um padrão que é auto-referenciado que eu utilizaria em PHP se eu tivesse que:

^(?<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: o PHP tem um filtro embutido para isso, que seria uma solução melhor do que este padrão.

Análise Regex101


2

Eu gerei o seguinte usando python e funcione com o módulo re. As declarações antecipadas garantem que o número correto de pontos ou dois pontos apareça no endereço. Não suporta IPv4 na notação 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)

2

Regexes para ipv6 podem ficar realmente complicados quando você considera endereços com ipv4 incorporado e endereços que são compactados, como você pode ver em algumas dessas respostas.

A biblioteca Java IPAddress de código aberto validará todas as representações padrão de IPv6 e IPv4 e também suporta comprimento de prefixo (e validação de tal). Isenção de responsabilidade: eu sou o gerente de projeto dessa biblioteca.

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

1

Em Java, você pode usar a classe de biblioteca sun.net.util.IPAddressUtil:

IPAddressUtil.isIPv6LiteralAddress(iPaddress);

3
sun.net. * é uma API privada.
David Kocher

1

É difícil encontrar uma expressão regular que funcione para todos os casos IPv6. Eles geralmente são difíceis de manter, não são facilmente legíveis e podem causar problemas de desempenho. Portanto, quero compartilhar uma solução alternativa que desenvolvi: Expressão regular (RegEx) para IPv6 separado do IPv4

Agora você pode perguntar: "Este método encontra apenas IPv6, como posso encontrar IPv6 em um texto ou arquivo?" Aqui estão os métodos para esse problema.

Observação : se você não quiser usar a classe IPAddress no .NET, também pode substituí-la pelo meu método . Ele também cobre o IPv4 mapeado e casos especiais, enquanto o IPAddress não cobre.

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

}

1

InetAddressUtilstem todos os padrões definidos. Acabei usando o padrão diretamente e estou colando aqui para referência:

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 

1

Usando Ruby? Experimente isto:

/^(((?=.*(::))(?!.*\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

1

Dependendo de suas necessidades, uma aproximação como:

[0-9a-f:]+

pode ser o suficiente (como com grepping de arquivo de log simples, por exemplo.)


0

Para usuários do PHP 5.2+ filter_varfunciona muito bem.

Eu sei que isso não responde à pergunta original (especificamente uma solução regex), mas eu postei isso na esperança de que possa ajudar alguém no 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);

0

Isso 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})$

2
Corresponde a endereços inválidos com 2 instâncias de ::. por exemplo2404:6800::4003:c02::8a
nhahtdh

corresponde a IPv4 inválido 666.666.666.666
Ryan Williams

0

Aqui está o que eu criei, usando um pouco de lookahead e grupos nomeados. É claro que é apenas IPv6, mas não deve interferir com padrões adicionais se você quiser adicionar 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})


0

Apenas combinando os locais de uma origem com colchetes incluídos. Eu sei que não é tão abrangente, mas em javascript os outros tinham problemas de rastreamento principalmente de não funcionar, então isso parece me dar o que eu precisava no momento. AF capitais extras também não são necessários.

^\[([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})\]

A versão de Jinnko é simplificada e melhor eu vejo.


0

Como afirmado acima, outra maneira de obter um analisador de validação de representação textual IPv6 é usar programação. Aqui está um que é totalmente compatível com RFC-4291 e RFC-5952. Escrevi este código em ANSI C (funciona com GCC, passei nos testes do Linux - funciona com clang, passei nos testes do FreeBSD). Portanto, ele depende apenas da biblioteca padrão ANSI C, portanto, pode ser compilado em qualquer lugar (eu o usei para análise IPv6 dentro de um módulo de kernel com 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;
}

-1

Experimente este pequeno one-liner. Deve corresponder apenas a endereços IPv6 descompactados / compactados válidos (sem híbridos de 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}/

Na verdade, os endereços IPv6 válidos incluem híbrido não compactado, compactado, híbrido não compactado e híbrido compactado. É preciso muito mais do que o necessário para corresponder a qualquer representação de texto válida de um endereço IPv6.
Ron Maupin

-2

O regex permite o uso de zeros à esquerda nas partes IPv4.

Algumas distros Unix e Mac convertem esses segmentos em octais.

Eu sugiro usar 25[0-5]|2[0-4]\d|1\d\d|[1-9]?\dcomo segmento IPv4.


-2

Se você quiser apenas IP-s normais (sem barras), aqui:

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

Eu o uso para meu marcador de sintaxe no aplicativo editor de arquivos hosts. Funciona como charme.


Não é possível que isso funcione decentemente, não pode corresponder a um único endereço ipv6 com um único dois-pontos, todas as suas correspondências estão em dois-pontos duplos e você exige explicitamente dois-pontos duplos para o seu último grupo, o resumo pode acontecer em qualquer lugar. .
KillianDS

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

Ainda errado, mas mesmo assim você vai acabar repetindo a resposta de JinnKo, que é boa o suficiente para propósitos simples, mas ainda tem falhas (não captura o resumo duplo e não permite quádruplos pontilhados, nem localhost, nem :: termination,. ..)
KillianDS
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.