Espressione regolare per abbinare il nome host DNS o l'indirizzo IP?


369

Qualcuno ha a portata di mano un'espressione regolare che corrisponderà a qualsiasi nome host DNS o indirizzo IP legale?

È facile scriverne uno che funzioni il 95% delle volte, ma spero di ottenere qualcosa che sia ben testato per abbinare esattamente le ultime specifiche RFC per i nomi host DNS.

Risposte:


535

È possibile utilizzare le seguenti espressioni regolari separatamente o combinandole in un'espressione OR congiunta.

ValidIpAddressRegex = "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$";

ValidHostnameRegex = "^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$";

ValidIpAddressRegex corrisponde a indirizzi IP validi e ValidHostnameRegex nomi host validi. A seconda della lingua che usi \ potrebbe essere necessario scappare con \.


ValidHostnameRegex è valido secondo RFC 1123 . Inizialmente, RFC 952 specificava che i segmenti del nome host non potevano iniziare con una cifra.

http://en.wikipedia.org/wiki/Hostname

La specifica originale dei nomi host in RFC 952 , prevedeva che le etichette non potevano iniziare con una cifra o con un trattino e non devono terminare con un trattino. Tuttavia, una specifica successiva ( RFC 1123 ) ha permesso alle etichette dei nomi host di iniziare con le cifre.

Valid952HostnameRegex = "^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])$";

3
Qui: stackoverflow.com/questions/4645126/… - Spiego che anche i nomi che iniziano con una cifra sono considerati validi. Inoltre, solo un punto è un problema discutibile. Sarebbe bello avere più feedback su questo.
BreakPhreak,

16
Potresti voler aggiungere IPv6. L'OP non ha specificato quale tipo di indirizzo. (A proposito, può essere trovato qui )
nuovo123456

32
Prima che le persone lo utilizzino ciecamente nel loro codice, nota che non è completamente accurato. Ignora RFC2181: "Il DNS stesso pone una sola restrizione sulle etichette particolari che possono essere utilizzate per identificare i record di risorse. Quella restrizione si riferisce alla lunghezza dell'etichetta e al nome completo. La lunghezza di ogni etichetta è limitata tra 1 e 63 ottetti. Un nome di dominio completo è limitato a 255 ottetti (inclusi i separatori). "
rublo,

7
@UserControl: i nomi host non latini (Punycoded) devono essere prima convertiti in formato ASCII ( éxämplè.com= xn--xmpl-loa1ab.com) e quindi convalidati.
Alix Axel,

6
La tua espressione nome host corrisponde ad alcuni valori non validi: ho provato 123.456.789.0e dice che è un nome host valido.
lbarreira,

62

Il nome host regex di smink non osserva la limitazione sulla lunghezza delle singole etichette all'interno di un nome host. Ogni etichetta con un nome host valido non può superare i 63 ottetti.

ValidHostnameRegex = "^ ([a-zA-Z0-9] | [a-zA-Z0-9] [a-zA-Z0-9 \ -] {0,61} [a-zA-Z0-9]) \
(\ ([A-zA-Z0-9] |. [A-zA-Z0-9] [a-zA-Z0-9 \ -] {0,61} [a-zA-Z0-9])) * $"

Si noti che la barra rovesciata alla fine della prima riga (sopra) è la sintassi della shell Unix per dividere la linea lunga. Non fa parte dell'espressione regolare stessa.

Ecco solo l'espressione regolare su una sola riga:

^ ([A-zA-Z0-9] | [a-zA-Z0-9] [a-zA-Z0-9 \ -] {0,61} [a-zA-Z0-9]) (\. ([a-zA-Z0-9] | [a-zA-Z0-9] [a-zA-Z0-9 \ -] {0,61} [a-zA-Z0-9])) * $

È inoltre necessario verificare separatamente che la lunghezza totale del nome host non deve superare 255 caratteri . Per ulteriori informazioni, consultare RFC-952 e RFC-1123.


6
Modello host eccellente. Probabilmente dipende dall'implementazione regex della propria lingua, ma per JS può essere leggermente modificato per essere più breve senza perdere nulla:/^[a-z\d]([a-z\d\-]{0,61}[a-z\d])?(\.[a-z\d]([a-z\d\-]{0,61}[a-z\d])?)*$/i
Punto

31

Per abbinare un indirizzo IP valido utilizzare la seguente regex:

(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}

invece di:

([01]?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\.([01]?[0-9][0-9]?|2[0-4][0-9]|25[0-5])){3}

Spiegazione

Molti motori regex corrispondono alla prima possibilità nella ORsequenza. Ad esempio, prova la seguente regex:

10.48.0.200

Test

Prova la differenza tra buono e cattivo


5
Non dimenticare che start ^ e end $ o qualcosa del genere 0.0.0.999 o 999.0.0.0 corrisponderanno. ;)
andreas,

1
sì per convalidare una stringa sono richiesti ^ e end $, ma se stai cercando un IP in un testo non usarlo.
Alban,

La "non avidità" indesiderata che identifichi si applica anche alle altre soluzioni per i nomi host. Vale la pena aggiungere questo alla tua risposta poiché gli altri non corrisponderanno al nome host completo. ad es. ([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*contro([a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]|[a-zA-Z0-9])(\.([a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])|[a-zA-Z0-9]))*
ergohack il

EDIT: in quanto sopra, utilizzare +alla fine invece di *vedere l'errore.
ergohack,

5

Non riesco a modificare il primo post, quindi aggiungerò la mia risposta qui.

Per nome host - risposta semplice, ad esempio esempio qui - http: //www.linuxinsight.com/how_to_grep_for_ip_addresses_using_the_gnu_egrep_utility.html

egrep '([[:digit:]]{1,3}\.){3}[[:digit:]]{1,3}'

Anche se il caso non tiene conto di valori come 0 nell'ottetto pugno e valori maggiori di 254 (indirizzo IP) o 255 (maschera di rete). Forse un'ulteriore dichiarazione if sarebbe di aiuto.

Per quanto riguarda il nome host DNS legale, a condizione che tu stia controllando solo i nomi host Internet (e non Intranet), ho scritto il seguente frammento, un mix di shell / php ma dovrebbe essere applicabile come qualsiasi espressione regolare.

prima vai sul sito web ietf, scarica e analizza un elenco di nomi di dominio legali di livello 1:

tld=$(curl -s http://data.iana.org/TLD/tlds-alpha-by-domain.txt |  sed 1d  | cut -f1 -d'-' | tr '\n' '|' | sed 's/\(.*\)./\1/')
echo "($tld)"

Questo dovrebbe darti un bel codice di re che controlla la legalità del nome di dominio principale, come .com .org o .ca

Quindi aggiungi la prima parte dell'espressione secondo le linee guida trovate qui l'inizio o la fine di un ottetto.

(([a-z0-9]+|([a-z0-9]+[-]+[a-z0-9]+))[.])+

Quindi metti tutto insieme (esempio PHP preg_match):

$pattern = '/^(([a-z0-9]+|([a-z0-9]+[-]+[a-z0-9]+))[.])+(AC|AD|AE|AERO|AF|AG|AI|AL|AM|AN|AO|AQ|AR|ARPA|AS|ASIA|AT|AU|AW|AX|AZ|BA|BB|BD|BE|BF|BG|BH|BI|BIZ|BJ|BM|BN|BO|BR|BS|BT|BV|BW|BY|BZ|CA|CAT|CC|CD|CF|CG|CH|CI|CK|CL|CM|CN|CO|COM|COOP|CR|CU|CV|CX|CY|CZ|DE|DJ|DK|DM|DO|DZ|EC|EDU|EE|EG|ER|ES|ET|EU|FI|FJ|FK|FM|FO|FR|GA|GB|GD|GE|GF|GG|GH|GI|GL|GM|GN|GOV|GP|GQ|GR|GS|GT|GU|GW|GY|HK|HM|HN|HR|HT|HU|ID|IE|IL|IM|IN|INFO|INT|IO|IQ|IR|IS|IT|JE|JM|JO|JOBS|JP|KE|KG|KH|KI|KM|KN|KP|KR|KW|KY|KZ|LA|LB|LC|LI|LK|LR|LS|LT|LU|LV|LY|MA|MC|MD|ME|MG|MH|MIL|MK|ML|MM|MN|MO|MOBI|MP|MQ|MR|MS|MT|MU|MUSEUM|MV|MW|MX|MY|MZ|NA|NAME|NC|NE|NET|NF|NG|NI|NL|NO|NP|NR|NU|NZ|OM|ORG|PA|PE|PF|PG|PH|PK|PL|PM|PN|PR|PRO|PS|PT|PW|PY|QA|RE|RO|RS|RU|RW|SA|SB|SC|SD|SE|SG|SH|SI|SJ|SK|SL|SM|SN|SO|SR|ST|SU|SV|SY|SZ|TC|TD|TEL|TF|TG|TH|TJ|TK|TL|TM|TN|TO|TP|TR|TRAVEL|TT|TV|TW|TZ|UA|UG|UK|US|UY|UZ|VA|VC|VE|VG|VI|VN|VU|WF|WS|XN|XN|XN|XN|XN|XN|XN|XN|XN|XN|XN|YE|YT|YU|ZA|ZM|ZW)[.]?$/i';

    if (preg_match, $pattern, $matching_string){
    ... do stuff
    }

Puoi anche aggiungere un'istruzione if per verificare che la stringa che stai controllando sia più corta di 256 caratteri - http://www.ops.ietf.org/lists/namedroppers/namedroppers.2003/msg00964.html


1
-1 perché corrisponde a indirizzi IP fasulli come "999.999.999.999".
bdesham,

1
"Anche se il caso non tiene conto di valori come 0 nell'ottetto del pugno e valori maggiori di 254 (indirizzo IP) o 255 (maschera di rete)."
Alex Volkov,

Ho visto che hai qualificato la tua risposta, sì. Ho annullato il voto perché quella parte della tua risposta non è ancora utile.
bdesham,

3

Vale la pena notare che ci sono librerie per la maggior parte delle lingue che lo fanno per te, spesso integrate nella libreria standard. E è probabile che quelle librerie vengano aggiornate molto più spesso del codice che hai copiato da una risposta Stack Overflow quattro anni fa e che hai dimenticato. E ovviamente analizzeranno anche l'indirizzo in una forma utilizzabile, piuttosto che darti una corrispondenza con un gruppo di gruppi.

Ad esempio, il rilevamento e l'analisi di IPv4 in (POSIX) C:

#include <arpa/inet.h>
#include <stdio.h>

int main(int argc, char *argv[]) {
  for (int i=1; i!=argc; ++i) {
    struct in_addr addr = {0};
    printf("%s: ", argv[i]);
    if (inet_pton(AF_INET, argv[i], &addr) != 1)
      printf("invalid\n");
    else
      printf("%u\n", addr.s_addr);
  }
  return 0;
}

Ovviamente, tali funzioni non funzioneranno se stai provando, ad esempio, a trovare tutti gli indirizzi validi in un messaggio di chat, ma anche lì, potrebbe essere più semplice utilizzare una regex semplice ma troppo zelante per trovare potenziali corrispondenze, quindi utilizzare il libreria per analizzarli.

Ad esempio, in Python:

>>> import ipaddress
>>> import re
>>> msg = "My address is 192.168.0.42; 192.168.0.420 is not an address"
>>> for maybeip in re.findall(r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}', msg):
...     try:
...         print(ipaddress.ip_address(maybeip))
...     except ValueError:
...         pass

2
def isValidHostname(hostname):

    if len(hostname) > 255:
        return False
    if hostname[-1:] == ".":
        hostname = hostname[:-1]   # strip exactly one dot from the right,
                                   #  if present
    allowed = re.compile("(?!-)[A-Z\d-]{1,63}(?<!-)$", re.IGNORECASE)
    return all(allowed.match(x) for x in hostname.split("."))

Potresti spiegare questa regex? Esattamente, cosa significano (?! -), (? <! -)?
Scriva il

1
@Scit, quelli si assicurano che non inizi o finisca con un carattere "-" se il tuo motore regex ne consente l'uso. Ad esempio, da Python o da Perl .
Impara il

1

Penso che questo sia il miglior regex di validazione IP. per favore controlla una volta !!!

^(([01]?[0-9]?[0-9]|2([0-4][0-9]|5[0-5]))\.){3}([01]?[0-9]?[0-9]|2([0-4][0-9]|5[0-5]))$

1
"^((\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])\.){3}(\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])$"

1

Funziona con indirizzi IP validi:

regex = '^([0-9]|[1-9][0-9]|[1][0-9][0-9]|[2][0-5][0-5])[.]([0-9]|[1-9][0-9]|[1][0-9][0-9]|[2][0-5][0-5])[.]([0-9]|[1-9][0-9]|[1][0-9][0-9]|[2][0-5][0-5])[.]([0-9]|[1-9][0-9]|[1][0-9][0-9]|[2][0-5][0-5])$'

1
/^(?:[a-zA-Z0-9]+|[a-zA-Z0-9][-a-zA-Z0-9]+[a-zA-Z0-9])(?:\.[a-zA-Z0-9]+|[a-zA-Z0-9][-a-zA-Z0-9]+[a-zA-Z0-9])?$/

0

Ecco una regex che ho usato in Ant per ottenere un IP host proxy o un nome host da ANT_OPTS. Questo è stato usato per ottenere l'IP proxy in modo da poter eseguire un test "isreachable" Ant prima di configurare un proxy per una JVM biforcuta.

^.*-Dhttp\.proxyHost=(\w{1,}\.\w{1,}\.\w{1,}\.*\w{0,})\s.*$

È \wproprio lì, non catturerà l'IP, solo il nome host in determinate situazioni.
Yaron,

0

Ho scoperto che funziona abbastanza bene per gli indirizzi IP. Si convalida come la risposta migliore ma si assicura anche che l'ip sia isolato, quindi nessun testo o più numeri / decimali sono dopo o prima dell'ip.

(?! <\ S)? (: (: \ D | [1-9] \ D | 1 \ d \ d | 2 [0-4] \ d | 25 [0-5]) \ b |. \ b) {7} (?! \ S)


Ho provato molto ma non riuscivo a capire 2 cose qui. 1. \ b specifica il limite di parole Perché stiamo usando \ b? qual è il confine? e 2. Perché funziona solo per {7} Da quello che ho capito, penso che dovrebbe essere {4} ma, non funziona. Opzionalmente, potresti dire perché stai usando blocchi non catturanti.
Srichakradhar,


0

prova questo:

((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)

funziona nel mio caso.


0

Per quanto riguarda gli indirizzi IP, sembra che ci sia un dibattito sull'opportunità di includere zeri iniziali. Una volta era una pratica comune ed è generalmente accettata, quindi direi che dovrebbero essere contrassegnati come validi indipendentemente dalla preferenza corrente. C'è anche una certa ambiguità sul fatto che il testo prima e dopo la stringa debba essere convalidato e, di nuovo, penso che dovrebbe. 1.2.3.4 è un IP valido ma 1.2.3.4.5 non lo è e né la parte 1.2.3.4 né la parte 2.3.4.5 devono tradursi in una corrispondenza. Alcune delle preoccupazioni possono essere gestite con questa espressione:

grep -E '(^|[^[:alnum:]+)(([0-1]?[0-9]{1,2}|2[0-4][0-9]|25[0-5])\.){3}([0-1]?[0-9]{1,2}|2[0-4][0-9]|25[0-5])([^[:alnum:]]|$)' 

La parte sfortunata qui è il fatto che la parte regex che convalida un ottetto si ripete come è vero in molte soluzioni offerte. Sebbene ciò sia migliore che per le istanze del pattern, la ripetizione può essere eliminata del tutto se sono supportate subroutine nel regex in uso. L'esempio seguente abilita queste funzioni con l' -Pinterruttore di grepe sfrutta anche la funzionalità lookahead e lookbehind. (Il nome della funzione che ho selezionato è 'o' per ottetto. Avrei potuto usare 'ottetto' come nome ma volevo essere conciso.)

grep -P '(?<![\d\w\.])(?<o>([0-1]?[0-9]{1,2}|2[0-4][0-9]|25[0-5]))(\.\g<o>){3}(?![\d\w\.])'

La gestione del punto potrebbe effettivamente creare falsi negativi se gli indirizzi IP si trovano in un file con testo sotto forma di frasi poiché il punto potrebbe seguire senza che fosse parte della notazione punteggiata. Una variante di quanto sopra risolverebbe che:

grep -P '(?<![\d\w\.])(?<x>([0-1]?[0-9]{1,2}|2[0-4][0-9]|25[0-5]))(\.\g<x>){3}(?!([\d\w]|\.\d))'

0
>>> my_hostname = "testhostn.ame"
>>> print bool(re.match("^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])$", my_hostname))
True
>>> my_hostname = "testhostn....ame"
>>> print bool(re.match("^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])$", my_hostname))
False
>>> my_hostname = "testhostn.A.ame"
>>> print bool(re.match("^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])$", my_hostname))
True

0

Il nuovo framework di rete ha inizializzatori disponibili per struct IPv4Address e struct IPv6Address che gestiscono molto facilmente la parte dell'indirizzo IP. Fare questo in IPv6 con un regex è difficile con tutte le regole di accorciamento.

Sfortunatamente non ho una risposta elegante per il nome host.

Si noti che il framework di rete è recente, quindi potrebbe costringerti a compilare per le versioni recenti del sistema operativo.

import Network
let tests = ["192.168.4.4","fkjhwojfw","192.168.4.4.4","2620:3","2620::33"]

for test in tests {
    if let _ = IPv4Address(test) {
        debugPrint("\(test) is valid ipv4 address")
    } else if let _ = IPv6Address(test) {
        debugPrint("\(test) is valid ipv6 address")
    } else {
        debugPrint("\(test) is not a valid IP address")
    }
}

output:
"192.168.4.4 is valid ipv4 address"
"fkjhwojfw is not a valid IP address"
"192.168.4.4.4 is not a valid IP address"
"2620:3 is not a valid IP address"
"2620::33 is valid ipv6 address"

-1

cosa ne pensi di questo?

([0-9]{1,3}\.){3}[0-9]{1,3}

E così è 9999999999.0.0.9999999999 :) Ma per la maggior parte dei programmatori, questo approccio breve sarà sufficiente.
andreas,

3
-1 perché corrisponde a indirizzi IP senza senso (come osserva @Shebuka).
bdesham,

-1

su php: filter_var(gethostbyname($dns), FILTER_VALIDATE_IP) == true ? 'ip' : 'not ip'


2
Mentre questo codice può rispondere alla domanda, generalmente la spiegazione a fianco del codice rende una risposta molto più utile. Si prega di modificare la tua risposta e di fornire un contesto e spiegazione.
user4642212,

E, a meno che non mi sbagli, FILTER_VALIDATE_IP è un valore solo PHP.
DonGar,

-2

Verifica nomi host come ... mywebsite.co.in, thangaraj.name, 18thangaraj.in, thangaraj106.in ecc.,

[a-z\d+].*?\\.\w{2,4}$

3
-1. L'OP ha chiesto qualcosa "ben testato per abbinare esattamente le ultime specifiche RFC", ma questo non corrisponde ad es. * .Museum, mentre corrisponderà a * .foo. Ecco un elenco di TLD validi.
bdesham,

Non sono sicuro che sia una buona idea inserire il plus all'interno della classe di caratteri (parentesi quadre), inoltre, ci sono TLD con 5 lettere ( ad esempio .expert ).
Yaron,

Il modo migliore per ottenere risultati con RFC è utilizzare le funzioni di sistema / lingua. inet_atonè abbastanza buono.
m3nda,

-2

Ho pensato a questo semplice schema di corrispondenza regex per la corrispondenza dell'indirizzo IP \ d + [.] \ D + [.] \ D + [.] \ D +


1111.1.1.1 non è un ip valido. Non c'è modo di testare davvero un formato ip se non ti preoccupi delle sottoreti. Dovresti almeno occuparti del numero di apparizioni con qualcosa di simile ^\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}e, naturalmente, che non sarà il modo corretto. Se hai un languaje per scrivere script, avrai sicuramente accesso alle sue funzioni di rete. Il modo migliore per controllare un IP REALE è quello di dire al sistema di convertire e ip nel suo formato giusto, quindi controlla vero / falso. In caso di Python che uso socket.inet_aton(ip). Hai bisogno di un caso di PHP inet_aton($ip).
m3nda,

Gli utenti di Python possono dare un'occhiata qui: gist.github.com/erm3nda/f25439bba66931d3ca9699b2816e796c
m3nda
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.