11550 sujets

JavaScript, DOM et API Web HTML5

Bonjour à tous,

Avis aux amateurs d'expressions régulières en javascript... Je n'arrive pas à construire une regex pour valider la syntaxe "IP /Masque", soit :


xxx.xxx.xxx.xxx /nn
avec xxx >= 0 et xxx <= 255, et nn <= 32 et nn >= 1


J'utilise déjà la regex suivante pour valider une adresse IP, à compléter peut-être ?


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


Merci pour votre aide,

Julien.
Modifié par Juuules (19 Jan 2011 - 11:01)
Donc cela donne :

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


Un groupe de capture <G2> tel que : (25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)

"25[0-5]" match 250 à 255
"2[0-4][0-9]" match 200 à 249
"[01]?[0-9][0-9]?" 100 à 199 mais aussi (car les ? rendent une classe optionnelle) 0 à 9 (juste la seconde classe), 10 à 99 et le tout match aussi les zeros en préfixe. Donc 0 à 199 avec éventuellement des zéros tels que 0n, 00n, 0nn

Donc pour résumer ce groupe capture tout les nombre entre 1 et 3 chiffres dont la valeur numérique va de 0 à 255 avec ou sans zéros non signifiants.

Un groupe de capture <G1> tel que : (<G2>\.){3}

match trois (et seulement 3) nombres entre 0 et 255 avec ou sans 0 (<G1>) suivis d'un point "\.". Exemple : "255.000.9."
On remarquera que l'utilisation du groupe est ici faite uniquement pour pouvoir utiliser le quantifier.

Un dernier groupe <G3> identique à <G2>

Le tout avec des ancres de début et fin de chaine ^ et $.

Donc cette expression valide une adresse IP.
Par contre elle ne fait que de la validation, il est impossible de l'utiliser pour extraire les différentes composantes, les groupes de capture n'étant pas placés de la bonne manière.

Exemple :

'255.002.03.4'.match(/^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/)
>> ["255.002.03.4", "03.", "03", "4"]


On a le match global, le groupe <G1> qui n'a pas d'intérêt, le groupe <G2> mais qui malheureusement ne retourne que la dernière des trois valeurs qu'il a matché et le groupe <G3>.

Pour faire de l'analyse et extraire les groupes cette expression serait meilleure mais plus verbeuse :

'255.002.03.4'.match(/^(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)$/)
>> ["255.002.03.4", "255", "002", "03", "4"]


Le retour de match est là beaucoup plus utile !

Enfin pour faire de la simple validation cette expression est moins couteuse que la première car elle ne capture rien, et est aussi moins longue :

'255.002.03.4'.match(/^(?[i]:[/i](?:25[0-5]|2[0-4]\d|[01]?\d\d?)(?:\.|$)){4}/)
>> ["255.002.03.4"]

Modifié par MonsieurY (19 Jan 2011 - 10:37)
Et pour la route, la même expression mais n'acceptant pas les zéros non signifiants :

'255.99.113.4'.match(/^(?[i]:[/i](?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d?)(?:\.|$)){4}/)
>> ["255.99.113.4"]

'255.99.113.04'.match(/^(?[i]:[/i](?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d?)(?:\.|$)){4}/)
>> null

Modifié par MonsieurY (19 Jan 2011 - 11:05)
Je te remercie de ta réponse MonsieurY.
Très instructif, et merci pour l'amélioration de la regex seulement ma question concernait surtout la manière dont ajouter à cette regex un bloc pour vérifier la présence d'un masque en fin de chaine... c'est à dire d'être capable de détecter la syntaxe suivante : "xxx.xxx.xxx.xxx /xx".

J'ai finalement réussi à pondre cela moi-même.. Dommage d'avoir perdu du temps sur quelque chose d'aussi bête, voilà ce que j'utilise :

RegExp( /^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?){1}(\s){1}(\/){1}([0-9]|1[0-9]|2[0-9]|3[0-2]){1}$/ );


Pas franchement optimisé mais efficace.

Merci encore, sujet résolu.
Effectivement j'avais mal compris la question initiale.
Par contre ton expression régulière match les masques égaux à zéros alors que tu spécifiait 0<n<33. De plus il y a pas mal de groupes inutiles par exemple avec des quantifiers de 1...

'255.99.113.4 /0'.match(/^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?){1}(\s){1}(\/){1}([0-9]|1[0-9]|2[0-9]|3[0-2]){1}$/)
>> ["255.99.113.4 /0", "113.", "113", "4", " ", "/", "0"]


Tu peux l'améliorer comme ça :

'255.99.113.4 /0'.match(/^(?[i]:[/i](?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d?)(?:\.|\s\/(?:[12]\d|3[0-2]|[1-9])$)){4}/)
>> null
'255.99.113.4 /32'.match(/^(?[i]:[/i](?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d?)(?:\.|\s\/(?:[12]\d|3[0-2]|[1-9])$)){4}/)
>> ["255.99.113.4 /32"]

Modifié par MonsieurY (19 Jan 2011 - 11:18)
Errata : il y a un cas non prévu dans l'expression précédente :

'255.99.113.4.'.match(/^(?[i]:[/i](?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d?)(?:\.|\s\/(?:[12]\d|3[0-2]|[1-9])$)){4}/)
>> ["255.99.113.4."]


Ce qui est bien évidemment faux.

L'expression ci-dessous est plus robuste :

'255.99.113.4.'.match(/^(?[i]:[/i](?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?=.)| \/(?:[12]\d|3[0-2]|[1-9])$)){4}$/)
>> null

'255.99.113.4.4'.match(/^(?[i]:[/i](?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?=.)| \/(?:[12]\d|3[0-2]|[1-9])$)){4}$/)
>> null

'255.99.113.4 /32'.match(/^(?[i]:[/i](?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?=.)| \/(?:[12]\d|3[0-2]|[1-9])$)){4}$/)
>> ["255.99.113.4 /32"]


Au passage histoire d'être plus strict j'ai changé le "\s" par un " " après tout dépends si tu applique la loi de Postel ou non.
Modifié par MonsieurY (19 Jan 2011 - 14:17)