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

Estou tendo problemas para gravar uma expressão regular que corresponda a endereços IPv6 válidos, incluindo aqueles em sua forma compactada (com os zeros :: 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.

Se eu puder contornar sua dúvida, considere usar a noção de Endereço da sua biblioteca de rede para analisar e verificar se há erros.

Eu imagino que em algum momento você queira fazer algo com esses endereços, então por que não ir direto para a fonte e ter certeza de que sua biblioteca de rede entenderá o endereço? Isso é melhor do que apenas esperar que o regex esteja prestes a ser postado aqui irá corresponder ao conceito de implementação do endereço.

Em Java, temos InetAddress . No .NET, temos o IPAddress . No .NET, você ainda tem o TryParse na class IPAddress para fazer esse teste para você!

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

Não consegui obter a resposta do @Factor Mystic para trabalhar com expressões regulares POSIX, então escrevi uma que trabalha com expressões regulares POSIX e expressões regulares PERL.

Deve corresponder:

  • Endereços IPv6
  • endereços IPv6 compactados sem zero ( seção 2.2 do rfc5952 )
  • Endereços IPv6 de link local com índice de zona ( seção 11 da rfc4007 )
  • Endereço IPv6-IPv6 Embutido ( seção 2 do rfc6052 )
  • Endereços IPv6 mapeados para IPv4 ( seção 2.1 do rfc2765 )
  • Endereços traduzidos para o IPv4 ( seção 2.1 do rfc2765 )

Expressão Regular do 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 divisão da expressão regular acima nos principais pontos OR 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 tornar o acima mais fácil de entender, 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

Os itens a seguir validarão 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' 

De ” regex IPv6 “:

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

Parece que você pode estar usando o Python. Se assim for, 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 

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

Eu teria que secundar fortemente a resposta de Frank Krueger .

Embora você diga que precisa de uma expressão regular para corresponder a um endereço IPv6, presumo que seja realmente necessário 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 por Factor Mystic é longa e complexa. É mais provável que funcione, mas você também deve considerar como você lidaria se falhasse inesperadamente. O ponto que estou tentando fazer aqui é que, se você não puder formar uma expressão regular obrigatória, não poderá depurá-la facilmente.

Se você não tem biblioteca adequada, pode ser melhor escrever sua própria rotina de validação IPv6 que não depende de expressões regulares. Se você escrevê-lo, você entende e, se entender, poderá adicionar comentários para explicá-lo, para que os outros também possam entendê-lo e, subsequentemente, mantê-lo.

Aja com caucanvas ao usar uma expressão regular cuja funcionalidade você não possa explicar para outra pessoa.

Essa expressão regular corresponderá aos endereços IPv6 e IPv4 válidos de acordo com a implementação do regex pelo GNU C ++ com o modo REGULAR ESTENDIDO 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*$" 

Eu não sou um especialista em Ipv6, mas acho que você pode obter um resultado muito bom com mais facilidade 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 dividi-lo em partes … esqueça. Eu omiti o não especificado (: 🙂 já que não adianta ter “endereço não especificado” no meu database.

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

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

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

Para IPv6 eu tenho algo parecido com isto. Isso, obviamente, não lida com os detalhes muito sutis do IPv6, já que os índices de zona são permitidos apenas em algumas classs de endereços IPv6. E esse regex não é escrito para captura de grupo, é apenas um tipo de correspondência de expressões regulares.

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 a endereços IPv6 com sufixo IPv4, a segunda parte corresponde a endereços IPv6, a última a indicar o índice de zonas):

 ( ( ::(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 poder regex (caso insensível, cercar com o que já precisava, como início / fim da 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]+)? 

Se você usar Perl tente Net :: IPv6Addr

 use Net::IPv6Addr; if( defined Net::IPv6Addr::is_ipv6($ip_address) ){ print "Looks like an ipv6 address\n"; } 

NetAddr :: IP

 use NetAddr::IP; my $obj = NetAddr::IP->new6($ip_address); 

Validate :: IP

 use Validate::IP qw'is_ipv6'; if( is_ipv6($ip_address) ){ print "Looks like an ipv6 address\n"; } 

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

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

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

O terminal Unix ou Mac OSx o retorna apenas a saída correspondente (ipv6), incluindo: 1

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

Obter todos os endereços IP (IPv4 ou IPv6) e correspondência de impressão 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]+)' 

Em Scala, use os conhecidos validadores do 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 o teste 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 } } 

Um regex simples que combine, 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 combina a compactação em qualquer lugar do endereço, embora não corresponda ao endereço de loopback :: 1. Acho isso um compromisso razoável para manter a regex simples.

Eu uso com sucesso isso em regras de seleção inteligente iTerm2 para quad-click endereços IPv6.

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

Agora você pode perguntar que “Este método só encontra IPv6, como posso encontrar o IPv6 em um texto ou arquivo?” Aqui estão os methods para esse problema também.

Nota : Se você não quiser usar a class IPAddress no .NET, também poderá substituí-la pelo meu método . Também abrange casos mapeados de IPv4 e especiais, enquanto o IPAddress não cobre.

 class IPv6 { public List FindIPv6InFile(string filePath) { Char ch; StringBuilder sbIPv6 = new StringBuilder(); List listIPv6 = new List(); 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 FindIPv6InText(string text) { StringBuilder sbIPv6 = new StringBuilder(); List listIPv6 = new List(); 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; } } } 

Observando os padrões incluídos nas outras respostas, há vários bons padrões que podem ser aprimorados referenciando grupos e utilizando lookaheads. Aqui está um exemplo de um padrão que é auto-referência que eu utilizaria no PHP se eu tivesse que:

 ^(?
(?[[:xdigit:]]{0,4}) # grab a sequence of up to 4 hex digits # and name this pattern for usage later (?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 possui um filtro interno para isso, que seria uma solução melhor que esse padrão.

Análise Regex101

Usando Ruby? Tente 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 

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

 [0-9a-f:]+ 

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

A regex a seguir é apenas para IPv6. Grupo 1 combina com o IP.

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

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

 IPAddressUtil.isIPv6LiteralAddress(iPaddress); 

Para usuários do PHP 5.2+, o filter_var funciona muito bem.

Eu sei que isso não responde à pergunta original (especificamente uma solução de 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); 

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

InetAddressUtils tem todos os padrões definidos. Eu acabei usando o padrão deles 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 

Aqui está o que eu criei, usando um pouco de lookahead e grupos nomeados. Isto é claro apenas IPv6, mas não deve interferir com padrões adicionais se você quiser adicionar o IPv4:

 (?=([0-9a-f]+(:[0-9a-f])*)?(?P::)(?!([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}) 

Você pode usar as ferramentas de shell ipextract que fiz para essa finalidade. Eles são baseados em regexp e grep.

Uso:

 $ ifconfig | ipextract6 fe80::1%lo0 ::1 fe80::7ed1:c3ff:feec:dee1%en0 

Eu gerou o seguinte usando python e trabalha com o re módulo. As asserções de look-ahead asseguram que o número correto de pontos ou dois pontos apareça no endereço. Não suporta o 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) 

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 dificuldade em rastrear problemas principalmente que não funciona, então isso parece me dar o que eu precisava por agora. capitais extras AF não são necessários também.

 ^\[([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.

Como dito acima, outra maneira de obter uma representação textual IPv6 que valide o analisador é usar a programação. Aqui está um que é totalmente compatível com RFC-4291 e RFC-5952. Eu escrevi este código em ANSI C (trabalha com o GCC, passou em testes no Linux – funciona com o clang, passou em testes no FreeBSD). Assim, ele depende apenas da biblioteca padrão ANSI C, então ela pode ser compilada em qualquer lugar (eu usei para análise IPv6 dentro de um módulo do kernel com FreeBSD).

 // IPv6 textual representation validating parser fully compliant with RFC-4291 and RFC-5952 // BSD-licensed / Copyright 2015-2017 Alexandre Fenyo #include  #include  #include  #include  #include  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; } 

Regexes for ipv6 can get really tricky when you consider addresses with embedded ipv4 and addresses that are compressed, as you can see from some of these answers.

The open-source IPAddress Java library will validate all standard representations of IPv6 and IPv4 and also supports prefix-length (and validation of such). Disclaimer: I am the project manager of that library.

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 } 

Try this small one-liner. It should only match valid uncompressed/compressed IPv6 addresses (no IPv4 hybrids)

 /(?!.*::.*::)(?!.*:::.*)(?!:[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}/ 

The regex allows the use of leading zeros in the IPv4 parts.

Some Unix and Mac distros convert those segments into octals.

I suggest using 25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d as an IPv4 segment.