Espressione regolare che corrisponde a indirizzi IPv6 validi


111

Ho problemi a scrivere un'espressione regolare che corrisponda a indirizzi IPv6 validi, inclusi quelli nella loro forma compressa (con ::o gli zeri iniziali omessi da ciascuna coppia di byte).

Qualcuno può suggerire un'espressione regolare che soddisfi il requisito?

Sto valutando di espandere ogni coppia di byte e abbinare il risultato con un'espressione regolare più semplice.


1
Dai un'occhiata a intermapper.com/ipv6validator .. si collega a questo script di test perl
Mottie

Ho provato tutte le risposte seguenti e non funzionano per tutti i miei casi di test e / o includono anche IPv4 che non è stato richiesto. Ho trovato questo per essere la soluzione più pulita finora: stackoverflow.com/a/21944928/3112803
gfrobenius

Risposte:


252

Non sono riuscito a far funzionare la risposta di @Factor Mystic con le espressioni regolari POSIX, quindi ne ho scritta una che funziona con le espressioni regolari POSIX e le espressioni regolari PERL.

Dovrebbe corrispondere:

Espressione regolare 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]))

Per facilità di lettura, la seguente è l'espressione regolare sopra divisa nei punti OR principali in linee separate:

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

Per rendere quanto sopra più facile da capire, il seguente codice "pseudo" replica quanto sopra:

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

Ho pubblicato uno script su GitHub che verifica l'espressione regolare: https://gist.github.com/syzdek/6086792


3
La tua regex IPv4 non corrisponde a IP come127.000.000.001
Kentzo

21
I segmenti IPv4 non devono includere zeri iniziali. Se è presente uno zero iniziale, il segmento IPv4 deve essere interpretato in ottale. Quindi l'IPV4SEG sopra è corretto nel non consentire "000". Tuttavia, consente "00" che non dovrebbe.
par

3
Non ha funzionato per me nel browser come mi sarei aspettato. Validated even reg.test ('3zzzzffe: 1900: 4545: 3: 200: f8ff: fe21: 67cf') che ovviamente non è un indirizzo IPv6 valido. Ha avuto risultati molto migliori con regex qui: nbviewer.ipython.org/github/rasbt/python_reference/blob/master/…
Capaj

7
fantastica regex ipv6. rilevato un piccolo bug con la sezione link local. avevi fe80dove dovrebbe essere qualcosa di simile [fF][eE]80e un ffffche dovrebbe essere qualcosa di simile[fF]{4}
user2831628

4
+1 per mostrare che le espressioni regolari possono essere (allo stesso modo di qualsiasi codice sorgente) effettivamente leggibili se si presta attenzione e le si formattano.
Natix

52

Quanto segue convaliderà gli indirizzi IPv4, IPv6 (completo e compresso) e IPv6v4 (completo e compresso):

'/^(?>(?>([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
Anche se la convalida di ip-s potrebbe essere eseguita come suggerisce Frank Krueger, questa soluzione è quella che risponde effettivamente alla domanda (anche se non l'ho ancora testata completamente) così come se hai molti IP che vuoi testare sintatticamente e magari corrispondere a una riga di testo, non puoi usare la tecnica di convalida IP.
Gyuri

Ciao, ho provato questa RegExp e non ha funzionato per me. Dice che D è un flag non valido e quando lo rimuovo dice "SyntaxError: invalid quantifier"
diosney

3
JavaScript implementa un sottoinsieme di espressioni regolari in stile Perl, non la totalità di PCRE. La mia regex non funzionerà senza alcune delle funzionalità avanzate di PCRE.
MichaelRushton

2
Questo fa eccezione per me in C #
sarat

1
Caso di test non riuscito: FE80: 0000: 0000: 0000: 0202: B3FF: FE1E: 8329 Utilizzo dell'ultima versione di Elixir in questa data, che utilizza PCRE sotto.
pmarreck

23

Sembra che tu stia usando Python. Se è così, puoi usare qualcosa del genere:

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

Non penso che tu debba avere IPv6 compilato in Python per ottenere inet_pton, che può anche analizzare gli indirizzi IPv4 se passi socket.AF_INETcome primo parametro. Nota: questo potrebbe non funzionare su sistemi non Unix.


4
È necessario specificare il tipo di eccezione nella exceptclausola. In caso contrario, exceptcatturerà tutto e potrebbe mascherare errori non correlati. Il tipo qui dovrebbe essere socket.error.
Ayman Hourieh,

A) inet_pton non genera altre eccezioni, a meno che i documenti non siano sbagliati, e B) anche se lo facesse, cos'altro restituiresti se non False?
Joe Hildebrand

2
Ri: altri errori ... se l'utente passa in una non stringa, TypeError viene mangiato. Chiaramente una lista non è un ipv6, ma probabilmente vorrei che fosse carpa che stavo passando nel tipo sbagliato.
Gregg Lind,

1
+1 Questo mi ha aiutato molto. Un paio di punti aggiuntivi che dovrebbero essere aggiunti: 1) socket.inet_pton può essere utilizzato per testare la validità di entrambe le famiglie di indirizzi IP (IP e IPv6). 2) I documenti qui ( docs.python.org/2/library/socket.html ) suggeriscono che questo è disponibile su piattaforme Unix. Potrebbe non essere disponibile su piattaforme Win.
mkoistinen

usando django e questo aiuta!
elad silver

23

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

45
L'espressione regolare come questa dovrebbe essere un "odore di codice" che forse le espressioni regolari non sono la soluzione migliore qui. (Anche se, immagino che l'operazione lo abbia chiesto ...)
Thanatos il

10
@ user712092 - tutti coloro che hanno visto una base di codice con
brutti occhi

2
Questa è una farsa completamente inutile per le RE. Il programma che lo ha generato non ha capito cosa stava facendo. Un umano non lo farebbe mai in questo modo. Non lasciarti ingannare dall'apparente complessità: le RE sono davvero "magia nera" per molte persone, ma non c'è motivo di collocarle su un altro pianeta!
Chuck Kollars

+1 ma OMG ci deve essere un modo migliore per farlo: P Per riferimento: per Rails questo potrebbe aiutare: stackoverflow.com/questions/16965697/…
Tilo

1
È davvero un odore di codice; tuttavia dopo aver dato un'occhiata vedrai che ogni regex è abbastanza concisa. Il problema è che ci sono diversi modelli creati dalla 'compressione' di ipv6: i due punti all'inizio, al centro e alla fine, oltre ai due punti doppi non puoi usarli di nuovo, in cima al totale i due punti prima e dopo il doppio devono sommarsi. Perl 6 potrebbe essere in grado di affrontare questo problema, ma va ben oltre la sintassi PCRE. (PS - Non conto l'ipv4 incorporato alla fine, che è più lungo della sezione ipv6!)
Gerard ONeill

11

Dovrei assecondare con forza la risposta di Frank Krueger .

Mentre dici che hai bisogno di un'espressione regolare per abbinare un indirizzo IPv6, presumo che ciò di cui hai veramente bisogno sia essere in grado di controllare se una determinata stringa è un indirizzo IPv6 valido. C'è una sottile ma importante distinzione qui.

C'è più di un modo per verificare se una determinata stringa è un indirizzo IPv6 valido e la corrispondenza delle espressioni regolari è solo una soluzione.

Usa una libreria esistente se puoi. La libreria avrà meno bug e il suo utilizzo risulterà in meno codice da mantenere.

L'espressione regolare suggerita da Factor Mystic è lunga e complessa. Molto probabilmente funziona, ma dovresti anche considerare come faresti a farcela se fallisce inaspettatamente. Il punto che sto cercando di sottolineare qui è che se non puoi formare tu stesso un'espressione regolare richiesta, non sarai in grado di eseguirne facilmente il debug.

Se non hai una libreria adatta, potrebbe essere meglio scrivere la tua routine di convalida IPv6 che non dipende dalle espressioni regolari. Se lo scrivi lo capisci e se lo capisci puoi aggiungere commenti per spiegarlo in modo che anche altri possano capirlo e successivamente mantenerlo.

Agisci con cautela quando usi un'espressione regolare la cui funzionalità non puoi spiegare a qualcun altro.


1
L'uso di due espressioni regolari, un'espressione liberale e un'espressione di eccezioni per intercettare indirizzi non validi consentiti dalla prima, potrebbe essere più semplice di un'espressione ( return ex1.match(S) && ! ex2.match(S)).
Raedwald

4
Stai presumendo che stia convalidando singoli IP quando sta quasi certamente cercando IP in un grande blocco di testo.
Navin

8

Non sono un esperto di Ipv6 ma penso che puoi ottenere un risultato abbastanza buono più facilmente con questo:

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

rispondere "è un ipv6 valido" mi sembra ok. Per scomporlo in parti ... dimenticalo. Ho omesso quello non specificato (: :) poiché non serve avere "indirizzo non specificato" nel mio database.

l'inizio: ^([0-9A-Fa-f]{0,4}:){2,7}<- corrisponde alla parte comprimibile, possiamo tradurre questo come: tra 2 e 7 due punti che possono avere un numero esadecimale tra di loro.

seguito da: [0-9A-Fa-f]{1,4}$<- un numero esadecimale (0 iniziale omesso) O ((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4}<- un indirizzo IPv4


1
+1 per essersi attenuti effettivamente alla domanda dei PO e presentare un'espressione regolare relativamente bella che in qualche modo funziona.
xebeche,

1
Questo non corrisponde a ":: 1"
lsalamon

Eh? Nella sintassi java regex corrisponde a:start() = 0, end() = 3 group(0) = "::1" group(1) = ":" group(2) = "1" group(3) = "null" group(4) = "null" group(5) = "null"
Remi Morin

Da qualche altra parte qualcuno mi avvisa di un problema con la mia regex, la parte compressa "::" può apparire solo una volta. Quindi ":: 1 :: 2" corrisponderebbe alla mia regex ma non è un IPV6 valido. Una seconda regex può convalidare questo caso. La raccomandazione completa era quella di utilizzare un parser stateful per la convalida. Sono d'accordo che il codice risultante sarà più facile da leggere e mantenere (e qualcuno probabilmente lo ha già codificato in un open source da qualche parte).
Remi Morin

8

Questo cattura anche il loopback (:: 1) e gli indirizzi ipv6. cambiato {} in + e messo: all'interno della prima parentesi quadra.

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

testato con ifconfig -a output http://regexr.com/

Terminale Unix o Mac OSx o opzione restituisce solo l'output corrispondente (ipv6) incluso :: 1

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

Ottieni tutti gli indirizzi IP (IPv4 O IPv6) e stampa la corrispondenza sul termine 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]+)'

Mi piace la semplicità. Questo alla fine ha funzionato per me:ip a | grep -Po '[\w:]+:+[\w:]+'
Noam Manos

Umorismo apprezzato!
Soumya Kanti

Quando eseguo ipconfig / all, il mio indirizzo IP termina con% 10, questa espressione non corrisponde a questa parte?
Peter

7

Questa espressione regolare corrisponderà a indirizzi IPv6 e IPv4 validi in conformità con l'implementazione GNU C ++ di regex con la modalità REGULAR EXTENDED utilizzata:

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

Attenzione! In Java, l'uso di InetAddress e delle classi correlate (Inet4Address, Inet6Address, URL) può comportare il traffico di rete!Ad esempio, risoluzione DNS (URL.equals, InetAddress dalla stringa!). Questa chiamata potrebbe richiedere molto tempo e si sta bloccando!

Per IPv6 ho qualcosa di simile. Questo ovviamente non gestisce i dettagli molto sottili di IPv6 come che gli indici di zona sono consentiti solo su alcune classi di indirizzi IPv6. E questa regex non è scritta per l'acquisizione di gruppo, è solo un tipo di regexp "corrisponde".

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

Schema (la prima parte corrisponde agli indirizzi IPv6 con il suffisso IPv4, la seconda parte corrisponde agli indirizzi IPv6, l'ultimo patrt l'indice di 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 qui la regex potrebbe (senza distinzione tra maiuscole e minuscole, surround con ciò che è mai necessario come inizio / fine riga, ecc.):

(?:
(?:
::(?:[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

La seguente regex è solo per IPv6. Il gruppo 1 corrisponde all'IP.

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

+1 Non è sempre necessario avere una perfetta regex super complessa che un essere umano non può capire. Userò questo perché capisco cosa fa e nel mio caso, posso essere sicuro che se ho qualcosa che assomiglia a un ipv6 valido, quindi è un ipv6 valido.
David L.

3
questo non corrisponderebbe a: fe80 :: 1 o 2342: 32fd :: 2d32
James

3

Una semplice regex che corrisponderà, ma non consiglierei per la convalida di alcun tipo è questa:

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

Nota che questo corrisponde alla compressione in qualsiasi punto dell'indirizzo, sebbene non corrisponda all'indirizzo di loopback :: 1. Trovo che questo sia un ragionevole compromesso per mantenere semplice la regex.

Lo uso con successo nelle regole di selezione intelligente di iTerm2 per fare quattro clic sugli indirizzi IPv6.


3
Volevi dire A-F, no A-Z! Si noti inoltre che si esclude la notazione quadrata puntata.
xebeche,


2

In Scala si usano i ben noti validatori 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)

Di seguito i test del metodo 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, afferma di controllare che sia un indirizzo valido, " Convalida se l'ip passato è un indirizzo IPv4 o IPv6 valido. ", Ma in realtà controlla solo che sia formattato come un indirizzo valido. Ad esempio, 1200:0000:AB00:1234:0000:2552:7777:1313è un formato valido per un indirizzo IPv6, ma non è un indirizzo IPv6 valido come restituisce il metodo di test. Scommetto che pensa che 241.54.113.65sia un indirizzo IPv4 valido.
Ron Maupin

2

Guardando i modelli inclusi nelle altre risposte, ci sono una serie di buoni modelli che possono essere migliorati facendo riferimento ai gruppi e utilizzando i lookahead. Ecco un esempio di un modello autoreferenziale che utilizzerei in PHP se dovessi:

^(?<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 ha un filtro incorporato per questo che sarebbe una soluzione migliore di questo modello.

Analisi Regex101


2

Ho generato quanto segue usando python e funziona con il modulo re. Le asserzioni anticipate garantiscono che nell'indirizzo venga visualizzato il numero corretto di punti o due punti. Non supporta IPv4 nella notazione 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

Le espressioni regolari per ipv6 possono diventare davvero complicate se si considerano indirizzi con ipv4 incorporato e indirizzi compressi, come si può vedere da alcune di queste risposte.

La libreria Java IPAddress open source convaliderà tutte le rappresentazioni standard di IPv6 e IPv4 e supporta anche la lunghezza del prefisso (e la convalida di tale). Disclaimer: sono il project manager di quella libreria.

Esempio di codice:

        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

In Java, puoi utilizzare la classe della libreria sun.net.util.IPAddressUtil:

IPAddressUtil.isIPv6LiteralAddress(iPaddress);

3
sun.net. * è un'API privata.
David Kocher

1

È difficile trovare un'espressione regolare che funzioni per tutti i casi IPv6. Di solito sono difficili da mantenere, non facilmente leggibili e possono causare problemi di prestazioni. Quindi, voglio condividere una soluzione alternativa che ho sviluppato: Regular Expression (RegEx) per IPv6 Separato da IPv4

Ora potresti chiedere: "Questo metodo trova solo IPv6, come posso trovare IPv6 in un testo o in un file?" Ecco i metodi anche per questo problema.

Nota : se non vuoi usare la classe IPAddress in .NET, puoi anche sostituirla con il mio metodo . Copre anche IPv4 mappato e anche casi speciali, mentre IPAddress non copre.

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

InetAddressUtilsha tutti i modelli definiti. Ho finito per usare direttamente il loro modello e lo incollo qui come riferimento:

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

Usi Ruby? Prova questo:

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

A seconda delle tue esigenze, un'approssimazione del tipo:

[0-9a-f:]+

potrebbe essere sufficiente (come con il semplice grepping di file di registro, ad esempio.)


0

Per utenti PHP 5.2+ filter_var funziona alla grande.

So che questo non risponde alla domanda originale (in particolare una soluzione regex), ma lo posto nella speranza che possa aiutare qualcun altro in 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

Funzionerà per 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
Corrisponde a indirizzi non validi con 2 istanze di ::. ad esempio2404:6800::4003:c02::8a
nhahtdh

corrisponde a IPv4 non valido 666.666.666.666
Ryan Williams

0

Ecco cosa mi è venuto in mente, usando un po 'di lookahead e gruppi denominati. Questo è ovviamente solo IPv6, ma non dovrebbe interferire con modelli aggiuntivi se si desidera aggiungere 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

Basta abbinare quelli locali da un'origine con parentesi quadre incluse. So che non è così completo ma in javascript gli altri avevano problemi di tracciamento difficili principalmente quello di non funzionare, quindi questo sembra farmi ottenere ciò di cui avevo bisogno per ora. non sono necessarie nemmeno le maiuscole extra AF.

^\[([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 versione di Jinnko è semplificata e vedo meglio.


0

Come detto sopra, un altro modo per ottenere un parser di convalida della rappresentazione testuale IPv6 è usare la programmazione. Eccone uno completamente compatibile con RFC-4291 e RFC-5952. Ho scritto questo codice in ANSI C (funziona con GCC, ha superato i test su Linux - funziona con clang, ha superato i test su FreeBSD). Quindi, si basa solo sulla libreria standard ANSI C, quindi può essere compilato ovunque (l'ho usato per l'analisi IPv6 all'interno di un modulo 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;
}

-1

Prova questa piccola battuta. Deve corrispondere solo a indirizzi IPv6 non compressi / compressi validi (non ibridi 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}/

In realtà, gli indirizzi IPv6 validi includono ibrido non compresso, compresso, ibrido non compresso e ibrido compresso. Ci vuole davvero molto di più di quello che hai per abbinare effettivamente qualsiasi rappresentazione di testo valida di un indirizzo IPv6.
Ron Maupin

-2

La regex consente l'uso di zeri iniziali nelle parti IPv4.

Alcune distribuzioni Unix e Mac convertono quei segmenti in ottali.

Suggerisco di utilizzare 25[0-5]|2[0-4]\d|1\d\d|[1-9]?\dcome segmento IPv4.


-2

Se vuoi solo IP-s normali (senza barre), qui:

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

Lo uso per il mio evidenziatore di sintassi nell'applicazione dell'editor di file host. Funziona come un fascino.


Non è possibile che funzioni in modo decente, non può corrispondere a un singolo indirizzo ipv6 con un solo due punti, tutte le corrispondenze sono su due punti doppi e richiedi esplicitamente due due punti per il tuo ultimo gruppo, il riepilogo può avvenire ovunque .. .
KillianDS

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

Ancora sbagliato, ma anche allora finirai per ripetere la risposta di JinnKo, che è abbastanza buona per scopi semplici, ma ha ancora dei difetti (non cattura il doppio riepilogo e non consente quad punteggiate, né localhost, né :: termination,. ..)
KillianDS
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.