Regex pour les adresses IPv4 : bien couvrir les nombres de 0 à 255
Une adresse IPv4, c'est quatre nombres de 0 à 255. Voici pourquoi le motif évident \d{1,3} laisse passer 999.999.999.999, comment décrire un octet avec l'alternance, que faire des zéros en tête, et comment trouver des adresses dans du texte.

· 7 min de lecture · Mis à jour le
/^(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)$/
à attraper
- 0
- 42
- 199
- 255
à épargner
- 256
- 300
- 07
- 1000
Une adresse IPv4, c'est quatre nombres séparés par des points, comme 192.168.1.1. Chaque nombre s'appelle un octet, et va de 0 à 255.
Ça semble facile à reconnaître, et le premier motif que la plupart des gens écrivent est court et faux. Cet article part de là, le corrige étape par étape, et termine par un motif pour trouver des adresses dans du texte. Tous les exemples sont interactifs : modifiez les motifs et regardez les lignes changer.
/^ ( (25[0-5]| 2[0-4]\d| 1\d\d| [1-9]?\d) \.){3} (25[0-5]| 2[0-4]\d| 1\d\d| [1-9]?\d)$/Quatre nombres de 0 à 255 séparés par des points, sans zéro en tête.
Accepte
- 192.168.1.1
- 10.0.0.1
- 255.255.255.0
Rejette
- 256.1.1.1
- 010.0.0.1
- 1.2.3
01Le motif évident
Quatre groupes de un à trois chiffres, séparés par des points :
/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/Doit correspondre4/4
- 192.168.1.1
- 8.8.8.8
- 999.999.999.999
- 300.1.2.3
Ne doit pas2/2
- 1.2.3
- 1.2.3.4.5
Il repère bien un mauvais nombre de parties. Et si vous parcourez des logs auxquels vous faites confiance, cela suffit peut-être. Mais comme validateur, il accepte tout jusqu'à 999.
La répétition peut être plus courte. Trois octets se terminent chacun par un point : regroupez « octet plus point » et répétez-le trois fois avec {3} :
/^(\d{1,3}\.){3}\d{1,3}$/02N'oubliez pas la barre oblique inverse
Dans un motif, un . seul veut dire « n'importe quel caractère ». Oubliez les barres obliques inverses, et les points ne désignent plus des points :
1234567 est le plus sournois. Chaque . correspond à un chiffre : le motif le lit comme 1, 3, 5, 7, avec 2, 4, 6 en guise de « points ».
03Un octet, de 0 à 255
Une regex n'a aucune idée de la valeur d'un nombre. Elle ne voit que des caractères. « De 0 à 255 » doit donc s'écrire sous forme de règles sur le texte, découpées en plages qui ont chacune une forme simple :
| Plage | Motif | Se lit |
|---|---|---|
| 250–255 | 25[0-5] |
25, puis 0 à 5 |
| 200–249 | 2[0-4]\d |
2, puis 0 à 4, puis n'importe quel chiffre |
| 100–199 | 1\d\d |
1, puis deux chiffres quelconques |
| 0–99 | [1-9]?\d |
un 1 à 9 facultatif, puis n'importe quel chiffre |
Reliez-les avec | et entourez-les d'un groupe :
/^(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)$/Doit correspondre6/6
- 0
- 9
- 42
- 199
- 249
- 255
Ne doit pas4/4
- 256
- 300
- 07
- 1000
04Les zéros en tête
Regardez la dernière branche : [1-9]?\d, et non \d{1,2}. C'est ce qui rejette 07 et 010. Un octet à deux chiffres doit commencer par 1 à 9.
C'est plus important qu'il n'y paraît. Certains outils lisent un zéro en tête comme un nombre octal. socket.inet_aton en Python, qui suit les vieilles règles réseau du C, transforme 010.0.0.1 en 8.0.0.1, car 10 en octal vaut 8. Si une partie de votre système lit 010 comme dix et une autre comme huit, elles ne parlent plus de la même adresse. Rejeter les zéros en tête évite toute la question.
05Le motif complet
Mettez le groupe de l'octet à la place de \d{1,3} :
/^((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)$/Doit correspondre4/4
- 0.0.0.0
- 10.0.0.1
- 192.168.1.1
- 255.255.255.0
Ne doit pas6/6
- 256.1.1.1
- 192.168.1.300
- 999.999.999.999
- 010.0.0.1
- 1.2.3
- 1.2.3.4.5
Il est long, mais parce que l'octet est écrit deux fois, pas parce qu'il est compliqué. Voici ce que {3} fait gagner par rapport à l'octet écrit quatre fois :
Plateau0.0.0.0 · 10.0.0.1 · 192.168.1.1 · 255.255.255.0 · 8.8.4.4 vs 256.1.1.1 · 10.0.0 · 1.2.3.4.5 · 192.168.1.300 · 010.0.0.1
- en toutes lettresrésout140
/^(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)$/ - avec un grouperésout75
/^((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)$/
06Trouver des adresses dans du texte
^ et $ ne fonctionnent que si toute la saisie est une adresse. Pour trouver des adresses dans une ligne de log, le réflexe habituel est de les remplacer par des limites de mot, \b. Ça marche presque :
/\b((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\b/Doit correspondre2/2
- server at 10.0.0.1.
- version 1.2.3.4.5
Ne doit pas1/1
- error 999.1.1.1
Ce que vous voulez vraiment, c'est « ni chiffre ni point juste avant, et plus rien qui prolonge l'adresse juste après ». C'est un travail pour les lookarounds :
/(?<![\d.])((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?!\.?\d)/Doit correspondre2/2
- server at 10.0.0.1.
- ping 8.8.8.8 now
Ne doit pas3/3
- version 1.2.3.4.5
- error 999.1.1.1
- build 1.2.3
Celui-ci fonctionne aussi avec le re de Python. Python n'accepte que les lookbehinds de largeur fixe, et (?<![\d.]) vérifie toujours exactement un caractère.
07Ou utilisez un analyseur
Si vous validez une saisie dans du code, la bibliothèque standard le fait déjà. En Python :
import ipaddress
ipaddress.ip_address("192.168.1.1") # IPv4Address('192.168.1.1')
ipaddress.ip_address("192.168.1.1").is_private # True
ipaddress.ip_address("256.1.1.1") # ValueError
Depuis Python 3.9.5, ipaddress rejette aussi les zéros en tête comme 010.0.0.1. Dans Node, net.isIPv4("010.0.0.1") vaut aussi false, et donne les mêmes réponses que le motif complet ci-dessus sur tous les exemples de cet article. Un analyseur gère aussi l'IPv6, qui demanderait une regex bien plus grosse.
08À vous de jouer
Le cœur de tout le motif, c'est l'octet. Saurez-vous l'écrire de mémoire ?
Attrapez les nombres de 0 à 255, épargnez tout le reste.
Cibles · 0/10 attrapées
- 0cible
- 7cible
- 42cible
- 99cible
- 100cible
- 199cible
- 200cible
- 249cible
- 250cible
- 255cible
Innocents · erreurs : 0
- 256innocent
- 260innocent
- 300innocent
- 999innocent
- 1000innocent
- 07innocent
- 007innocent
Tapez une regex — le plateau se met à jour en direct.
09Récapitulatif
\d{1,3}accepte de 0 à 999. Utilisez(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)pour un octet.- Échappez chaque point :
\.. - Répétez avec un groupe :
(octet\.){3}octet. - Utilisez
[1-9]?\dpour les petits nombres afin de rejeter les zéros en tête. - Dans du texte, utilisez
(?<![\d.])et(?!\.?\d)plutôt que\b. - Dans du code, préférez
ipaddress(Python) ounet.isIPv4(Node).
10Continuez à vous entraîner
- La section du guide sur l'alternance couvre le
|qui construit l'octet. - Essayez la chasse du jour, ou parcourez les plateaux passés dans les archives.