mardi 20 mars 2018

Expressions régulières (RegEx)

Windows PowerShell utilise les expressions régulières (RegEx) pour déterminer si une chaine de caractères est conforme au format définit par l'expression régulière. Pour comparer une chaine de caractères avec une RegEx, Windows PowerShell utilise -match -notmatch, -cmatch, -notcmatch.

Principe du RegEx.


Une expression régulière est une chaîne de caractères représentant un ensemble de chaîne de caractères possibles. Dit comme ça ce ne parle pas forcement à tout le monde. Je vais essayer d'expliquer ça plus simplement. Imaginez que vous voulez rechercher le fichier "toto.txt"sur votre disque. Dans le champ de recherche vous utilisez le caractères génériques * pour dire au système de trouver tout les fichiers commençant par "toto" (ex : toto*). Le système va alors afficher des fichiers commençant par "toto" comme "toto1.txt", "toto.xml", etc. Le RegEx c'est pareil, mais avec des caractères génériques infiniment plus élaborés.

Note : Oui je sais, le caractère générique * n'est pas interprété pareil dans la recherche de fichier que dans le RegEx, mais c'est pour l'explication du principe de base ... "Il écoute vraiment rien Hervé" ^^.

Les bases de l'expression régulière.


^ = En début de chaine signifie "commence par".
^ = En milieu de chaine ce symbole représente la négation.
$ = En fin de chaine signifie "se termine par".
\w = [a-zA-Z0-9_]
\d = Contient au moins 1 chiffre.
\s = Contient au moins 1 espace.
\D = Ne contient aucun chiffre.
\S = Ne contient aucun espace.
[] = Liste ou range de caractère ex: [a-z] tout les caractères de "a" à "z".
{} = Longueur de la chaine à valider ex: {1,5} = 1 à 5 caractères.
{5} = Longueur exacte de la chaine (ici 5 caractère).
{5,} = Longueur au moins de 5 caractères (de 5 à n).
{5,9} = Longueur de 5 à 9 caractères.
* = N'importe quel longueur de 0 à n caractères.
+ = N'importe quel longueur de 1 à n caractères.
? = Indique que la condition précédente est optionnel.
| = Indique le choix entre deux conditions (Ou).

Exemples :
[a-z]* = Chaine alphabétique de longueur de 0 à n caractères.
[a-z]+ = Chaine alphabétique de longueur de 1 à n caractères.
[a-z]{1,12} = Chaine alphabétique de longueur de 1 à 12 caractères.
\d{1,6} = Nombre de 0 à 999999.
[:;,.] = Liste de caractères.
([a-z]+\d{1,4})+ = Le (...)+ indique une structure répétable de 1 à n fois.

Les comparaisons :
-match = Correspond à ... (insensible à la casse).
-notmatch = Ne correspond pas à ... (insensible à la casse).
-cmatch = Correspond à ... (sensible à la casse).
-cnotmatch = Ne correspond pas à ... (sensible à la casse).

Caractère d'échappement :
En dehors des cas vu précédemment, la barre oblique inverse "\" est utilisée dans une expression régulière pour indiquer que le caractère suivant doit être interprété littéralement. Par exemple :
\\ = \
\. = .
\+ = +
\* = *

Exemples classiques.


Texte avec caractères alphabétiques :
$texte = "Jumbor"
$texte -match  "^[a-z]*$"
$texte -cmatch "^[a-zA-Z]*$"

Texte en minuscule uniquement :
$texte = "jumbor"
$texte -cmatch "^[a-z]*$"


Texte en majuscule uniquement :
$texte = "JUMBOR"
$texte -cmatch "^[A-Z]*$"


Texte de 1 à 12 caractères alphabétiques :
$texte = "Jumbor"
$texte -match "^[a-z]{1,12}$"


Texte commençant par une majuscule, et de 1 à 12 caractères alphabétiques :
$texte = "Jumbor"
$texte -cmatch "^[A-Z]{1}[a-zA-Z]{0,11}$"


Texte de 1 à 12 caractères sans espace et sans chiffre :
$texte = "Jumbor"
$texte -match "^\S\D{1,12}$"


Chiffre de 0 à 99999 :
$texte = "12"
$texte -match "^\d{1,5}$"


Ne contient pas ces caractères :
$texte = "Jumbor"
$texte -notmatch "[:;,.]"


Contient que des chiffres et lettres :
$texte = "Jumbor12"
$texte -match "^[0-9a-z]*$"
$texte -cmatch "^[0-9a-zA-Z]*$"

Exemples avancés.


Vérifier le format "Prénom NOM" avec des prénoms simples :
$texte = "Barus CROW"
$texte -cmatch "^[A-Z]{1}[a-zA-Z]* [A-Z]*$"


Idem en ajoutant des prénoms composés en "Prénom-Prénom" :
$texte = "Jean-Pierre CROW"
$texte -cmatch "^(([A-Z]{1}[a-z]*)|([A-Z]{1}[a-z]*-[A-Z]{1}[a-z]*)) [A-Z]*$"


Idem en ajoutant des caractères accentué :
$texte = "Loïc CROW"
$texte -cmatch "^(([A-Z]{1}[éïëèa-z]*)|([A-Z]{1}[éïëèa-z]*-[A-Z]{1}[éïëèa-z]*)) [A-Z]*$"


Vérifier une adresse ip4 :
$ip = "192.168.1.1"
$ip -match "\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"


Vérifier une adresse ip4 plus précisément :
$ip = "192.168.1.1"
$ip -match "((\b(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]?)\b)"


Vérifier une adresse email en particulier :
$email = "Jumbor@sekki.fr"
$email -match "^(([a-z]+)|([a-z]+\.[a-z]+))@sekki.fr$"


Vérifier une adresse mail générique :
$email = "Jumbor@sekki.fr"
$email -match "^(([a-z]+)|([a-z]+\.[a-z]+))@[a-z]+\.[a-z]+$"


Vérifier une adresse DNS simple :
$dns = "powershell.sekki.fr"
$site -match $dns -match "^([a-z]+\.)*([a-z]+)$"


Vérifier un site web :
$site = "http://powershell.sekki.fr"
$site -match "^(http://|https://|ftp://)([a-z]+\.)*([a-z]+)$"

Extraire une chaine en RegEx.


Exemple 1 :
$text = "Mon numéro de téléphone n'est pas le 06-11-22-33-44 !!!"
$phone = [regex]::match($text,'((\d{2}(-|\.){0,1}){5})').Value

Remplacer une chaine en RegEx.


Remplace une Ip dans le texte :
$text = "Serveur;Site;10.112.120.6;Type"
$rtn = [regex]::replace($text,'((\d{1,3}(\.){0,1}){4})','xxx.xxx.xxx.xxx')


#Remplace le début d'une Ip dans le texte :
$text = "Serveur;Site;10.112.120.6;Type"
$ip1 = [regex]::match($text,'((\d{1,3}(\.){0,1}){4})').Value
$ip2 = [regex]::replace($ip1,'^(\d{1,3}(\.))','xxx.')
$rtn = [regex]::replace($text,'((\d{1,3}(\.){0,1}){4})',$($ip2))