Expression régulière pour correspondre au nom d'hôte DNS ou à l'adresse IP?


369

Quelqu'un a-t-il une expression régulière à portée de main qui correspondra à n'importe quel nom d'hôte DNS légal ou adresse IP?

Il est facile d'en écrire un qui fonctionne 95% du temps, mais j'espère obtenir quelque chose de bien testé pour correspondre exactement aux dernières spécifications RFC pour les noms d'hôte DNS.

Réponses:


535

Vous pouvez utiliser les expressions régulières suivantes séparément ou en les combinant dans une expression OR conjointe.

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 correspond aux adresses IP valides et aux noms d'hôte valides ValidHostnameRegex . Selon la langue que vous utilisez, \ pourrait devoir être échappé avec \.


ValidHostnameRegex est valide selon la RFC 1123 . À l'origine, la RFC 952 spécifiait que les segments de nom d'hôte ne pouvaient pas commencer par un chiffre.

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

La spécification d'origine des noms d'hôtes dans la RFC 952 , stipulait que les étiquettes ne pouvaient pas commencer par un chiffre ou par un trait d'union et ne devaient pas se terminer par un trait d'union. Cependant, une spécification ultérieure ( RFC 1123 ) a permis aux étiquettes de nom d'hôte de commencer par des chiffres.

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
Ici: stackoverflow.com/questions/4645126/… - J'explique que les noms commençant par un chiffre sont également considérés comme valides. En outre, un seul point est un problème discutable. Ce serait formidable d'avoir plus de commentaires à ce sujet.
BreakPhreak

16
Vous voudrez peut-être ajouter IPv6. L'OP n'a pas précisé quel type d'adresse. (À propos, il peut être trouvé ici )
new123456

32
Avant que les gens l'utilisent aveuglément dans leur code, notez qu'il n'est pas complètement précis. Il ignore la RFC2181: "Le DNS lui-même ne place qu'une seule restriction sur les étiquettes particulières qui peuvent être utilisées pour identifier les enregistrements de ressources. Cette restriction se rapporte à la longueur de l'étiquette et au nom complet. La longueur d'une étiquette est limitée entre 1 et 63 octets. Un nom de domaine complet est limité à 255 octets (y compris les séparateurs). "
rouble

7
@UserControl: les noms d'hôtes non latins (punycodés) doivent d'abord être convertis au format ASCII ( éxämplè.com= xn--xmpl-loa1ab.com) puis validés.
Alix Axel

6
Votre expression de nom d'hôte correspond à des valeurs non valides: j'ai essayé 123.456.789.0et il est indiqué que c'est un nom d'hôte valide.
lbarreira

62

Le regex de nom d'hôte de smink n'observe pas la limitation de la longueur des étiquettes individuelles dans un nom d'hôte. Chaque étiquette d'un nom d'hôte valide ne doit pas dépasser 63 octets.

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])) * $ "

Notez que la barre oblique inversée à la fin de la première ligne (ci-dessus) est la syntaxe du shell Unix pour diviser la longue ligne. Cela ne fait pas partie de l'expression régulière elle-même.

Voici juste l'expression régulière seule sur une seule ligne:

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

Vous devez également vérifier séparément que la longueur totale du nom d'hôte ne doit pas dépasser 255 caractères . Pour plus d'informations, veuillez consulter RFC-952 et RFC-1123.


6
Excellent modèle d'hôte. Cela dépend probablement de l'implémentation de l'expression rationnelle de son langage, mais pour JS, il peut être légèrement ajusté pour être plus bref sans rien perdre:/^[a-z\d]([a-z\d\-]{0,61}[a-z\d])?(\.[a-z\d]([a-z\d\-]{0,61}[a-z\d])?)*$/i
Point

31

Pour faire correspondre une adresse IP valide , utilisez l'expression régulière suivante:

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

au lieu de:

([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}

Explication

De nombreux moteurs d'expression régulière correspondent à la première possibilité de la ORséquence. Par exemple, essayez l'expression régulière suivante:

10.48.0.200

Tester

Testez la différence entre le bon et le mauvais


5
N'oubliez pas start ^ et end $ ou quelque chose comme 0.0.0.999 ou 999.0.0.0 correspondra aussi. ;)
andreas

1
oui pour valider une chaîne start ^ et end $ sont requis, mais si vous recherchez une IP dans un texte ne l'utilisez pas.
Alban

La «non-gourmandise» involontaire que vous identifiez s'applique également aux autres solutions de nom d'hôte. Il serait utile d'ajouter cela à votre réponse car les autres ne correspondront pas au nom d'hôte complet. par exemple ([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]))*versus([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

EDIT: Dans ce qui précède, utilisez +à la fin au lieu de *pour voir l'échec.
ergohack

5

Je ne semble pas être en mesure de modifier le premier article, alors j'ajouterai ma réponse ici.

Pour le nom d'hôte - réponse facile, sur l'exemple egrep ici - http: //www.linuxinsight.com/how_to_grep_for_ip_addresses_using_the_gnu_egrep_utility.html

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

Bien que le cas ne prenne pas en compte les valeurs comme 0 dans le premier octet, et les valeurs supérieures à 254 (adresses IP) ou 255 (masque de réseau). Peut-être un énoncé supplémentaire si cela pourrait aider.

En ce qui concerne le nom d'hôte DNS légal, à condition que vous ne recherchiez que les noms d'hôte Internet (et non intranet), j'ai écrit ce qui suit, un mélange de shell / php mais il devrait être applicable comme toute expression régulière.

allez d'abord sur le site Web de l'ietf, téléchargez et analysez une liste de noms de domaine de niveau 1 légal:

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

Cela devrait vous donner un bon morceau de code re qui vérifie la légalité du nom de domaine supérieur, comme .com .org ou .ca

Ajoutez ensuite la première partie de l'expression conformément aux directives trouvées ici - http: //www.domainit.com/support/faq.mhtml?category=Domain_FAQ&question=9 (toute combinaison alphanumérique et le symbole «-», le tiret ne doit pas être dans le début ou la fin d'un octet.

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

Ensuite, mettez tout cela ensemble (exemple 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
    }

Vous pouvez également ajouter une instruction if pour vérifier que la chaîne que vous vérifiez est inférieure à 256 caractères - http://www.ops.ietf.org/lists/namedroppers/namedroppers.2003/msg00964.html


1
-1 car cela correspond à de fausses adresses IP comme «999.999.999.999».
bdesham

1
"Bien que le cas ne prenne pas en compte des valeurs comme 0 dans le premier octet, et des valeurs supérieures à 254 (adresses IP) ou 255 (masque de réseau)."
Alex Volkov

J'ai vu que vous avez nuancé votre réponse, oui. J'ai voté contre parce que cette partie de votre réponse n'est toujours pas utile.
bdesham

3

Il convient de noter qu'il existe des bibliothèques pour la plupart des langues qui le font pour vous, souvent intégrées à la bibliothèque standard. Et ces bibliothèques sont susceptibles d'être mises à jour beaucoup plus souvent que le code que vous avez copié une réponse Stack Overflow il y a quatre ans et oublié. Et bien sûr, ils analysent généralement l'adresse sous une forme utilisable, plutôt que de simplement vous donner un match avec un groupe de groupes.

Par exemple, détecter et analyser IPv4 dans (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;
}

De toute évidence, ces fonctions ne fonctionneront pas si vous essayez, par exemple, de trouver toutes les adresses valides dans un message de discussion, mais même là, il peut être plus facile d'utiliser une expression rationnelle simple mais trop zélée pour trouver des correspondances potentielles, puis utilisez le bibliothèque pour les analyser.

Par exemple, en 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("."))

Pourriez-vous expliquer cette expression régulière? Que signifie exactement (?! -), (? <! -)?
Scit

1
@Scit, ceux-ci s'assurent qu'il ne démarre ni ne se termine par un caractère "-" si votre moteur d'expression régulière autorise leur utilisation. Par exemple, à partir de Python ou de Perl .
Apprendre le

1

Je pense que c'est le meilleur regex de validation Ip. veuillez le vérifier une fois !!!

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

Cela fonctionne pour les adresses IP valides:

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

Voici une expression régulière que j'ai utilisée dans Ant pour obtenir une adresse IP d'hôte proxy ou un nom d'hôte à partir d'ANT_OPTS. Cela a été utilisé pour obtenir l'IP du proxy afin que je puisse exécuter un test Ant "isreachable" avant de configurer un proxy pour une JVM fourchue.

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

C'est \wjuste là, il ne capturera pas IP, seulement le nom d'hôte dans certaines situations.
Yaron

0

J'ai trouvé que cela fonctionne assez bien pour les adresses IP. Il valide comme la première réponse, mais il s'assure également que l'ip est isolé afin qu'aucun texte ou plusieurs nombres / décimales ne soient après ou avant l'ip.

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


J'ai beaucoup essayé mais je ne pouvais pas comprendre 2 choses ici. 1. \ b spécifie la limite des mots Pourquoi utilisons-nous \ b? quelle est la limite? et 2. Pourquoi ça marche seulement pour {7} D'après ce que j'ai compris, je pense que ça devrait être {4} mais ça ne marche pas. En option, vous pouvez expliquer pourquoi utilisez-vous des blocs non capturants.
Srichakradhar


0

essaye ça:

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

cela fonctionne dans mon cas.


0

En ce qui concerne les adresses IP, il semble qu'il y ait un débat sur l'opportunité d'inclure des zéros de tête. C'était autrefois la pratique courante et généralement acceptée, donc je dirais qu'ils devraient être signalés comme valides, quelle que soit la préférence actuelle. Il existe également une certaine ambiguïté quant à savoir si le texte avant et après la chaîne doit être validé et, encore une fois, je pense que oui. 1.2.3.4 est une adresse IP valide mais 1.2.3.4.5 ne l'est pas et ni la partie 1.2.3.4 ni la partie 2.3.4.5 ne devraient donner lieu à une correspondance. Certaines des préoccupations peuvent être traitées avec cette expression:

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 partie malheureuse ici est le fait que la partie regex qui valide un octet est répétée comme cela est vrai dans de nombreuses solutions proposées. Bien que cela soit meilleur que pour les instances du modèle, la répétition peut être entièrement éliminée si les sous-programmes sont pris en charge dans l'expression régulière utilisée. L'exemple suivant active ces fonctions avec le -Pcommutateur de grepet tire également parti des fonctionnalités de recherche et de recherche. (Le nom de la fonction que j'ai sélectionné est «o» pour octet. J'aurais pu utiliser «octet» comme nom mais je voulais être concis.)

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 gestion du point peut en fait créer un faux négatif si les adresses IP sont dans un fichier avec du texte sous forme de phrases car la période a pourrait suivre sans qu'il fasse partie de la notation en pointillé. Une variante de ce qui précède résoudrait cela:

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

La nouvelle infrastructure réseau a des initialiseurs disponibles pour struct IPv4Address et struct IPv6Address qui gèrent très facilement la partie adresse IP. Faire cela en IPv6 avec une expression régulière est difficile avec toutes les règles de raccourcissement.

Malheureusement, je n'ai pas de réponse élégante pour le nom d'hôte.

Notez que l'infrastructure réseau est récente, elle peut donc vous obliger à compiler pour les versions récentes du système d'exploitation.

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

que dis-tu de ça?

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

Et il en va de même pour 9999999999.0.0.9999999999 :) Mais pour la plupart des programmeurs, cette courte approche suffira.
andreas

3
-1 car cela correspond à des adresses IP non-sens (comme le note @Shebuka).
bdesham

-1

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


2
Bien que ce code puisse répondre à la question, généralement une explication à côté du code rend la réponse beaucoup plus utile. Veuillez modifier votre réponse et fournir un contexte et une explication.
user4642212

Et, sauf erreur, FILTER_VALIDATE_IP est une valeur PHP uniquement.
DonGar

-2

Vérification des noms d'hôte comme ... mywebsite.co.in, thangaraj.name, 18thangaraj.in, thangaraj106.in etc.,

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

3
-1. L'OP a demandé quelque chose de «bien testé pour correspondre exactement aux dernières spécifications RFC», mais cela ne correspond pas par exemple à * .museum, alors qu'il correspondra à * .foo. Voici une liste de TLD valides.
bdesham

Je ne suis pas sûr que ce soit une bonne idée de mettre le plus à l'intérieur de la classe de caractères (crochets), en plus, il y a des TLD avec 5 lettres ( .expert par exemple).
Yaron

La meilleure façon d'accomplir avec RFC est d'utiliser les fonctions système / langage. inet_atonest assez bon.
m3nda

-2

J'ai pensé à ce modèle de correspondance d'expression régulière simple pour la correspondance d'adresse IP \ d + [.] \ D + [.] \ D + [.] \ D +


1111.1.1.1 n'est pas une adresse IP valide. Il n'y a aucun moyen de vraiment tester un format IP si vous ne faites pas attention aux sous-réseaux. Vous devriez au moins faire attention au nombre d'apparitions avec quelque chose comme ^\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}et bien sûr, ce ne sera pas la bonne façon. Si vous avez une langue pour écrire un script, vous aurez certainement accès à ses fonctions réseau. La meilleure façon de vérifier une IP RÉELLE est de dire au système de convertir et d'IP à son bon format puis de vérifier vrai / faux. En cas de Python j'utilise socket.inet_aton(ip). Cas de PHP u besoin inet_aton($ip).
m3nda

Les utilisateurs de Python peuvent jeter un œil ici: gist.github.com/erm3nda/f25439bba66931d3ca9699b2816e796c
m3nda
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.