Les REGEX (REGular EXpressions ou expressions rationnelles) sont une méthode permettant de décrire des chaînes de caractères afin de les rechercher, contrôler (contrôle de saisie dans un formulaire web par exemple) et à fin de les manipuler : ré-ordonnér, recherche/remplace pour adapter un fichier texte ou CSV, renommer des fichiers, changer du code dans un programme...
Les logiciels exploitants cette méthode sont LibreOffice, le(s) shell(s) GNU/Linux, vim ... sous windows, notepad++
mon but n'étant pas d'être exaustif sur ce sujet,
Quelques liens sur les REGEX :
https://nppmanuel.nliautaud.fr/expressions-regulieres?id=articles/notepadpp/expreg
http://www.regular-expressions.info/tutorial.html (en)
http://www.vimregex.com/ (en) utilisation des regex dans vim
http://dridk.me/expression-reguliere.html
https://www.touticphoto.fr/faq/26-commande-find-sous-linux-avec-l-option-regex
https://linuxfr.org/news/travailler-avec-des-expressions-rationnelles#grep-est-mieux-avec--e
Pour tester des regex en ligne:
Mon objectif ici est de compléter ce que je n'ai pas trouvé dans les liens ci-dessus, en particulier, la gestion des codages de caractères. Il ne suffit généralement pas de mettre èé sauf avec UTF-8 et encore… cf. § ci-dessous (une raison de plus pour utiliser ce charset) entre les crochets pour que le regex voit les caractères accentués. En effet pour le charset ISO/IEC 8859-1, il faut plutôt les "échaper" avec \xE8-\xE9 (respectivement è et é).
http://www.developpez.net/forums/d686837/php/langage/regex/lettre-accentue-e-e-a-u-non-traite/
http://ram-0000.developpez.com/tutoriels/cpp/boost-regex/
http://en.wikipedia.org/wiki/ISO/IEC_8859-1
Bien prendre en compte le codage des caractères accentués et autres
Codant depuis 2018 essentiellement en PHP, j'ai eu a utiliser les REGEX sur des mots accentués. Le PHP et ses fonctions preg_…
sont basées sur PCRE et supportent donc l'utilisation des modèles (pattern) suivants :
solution classique (insuffisante pour gérer tous les cas) | solution avancée |
|
|
[a-zéèêïëç] |
|
source (EN) : https://www.regular-expressions.info/unicode.html
Renommage ou recherche avec les REGEX
Exemple : dans mon article renommage-photos-en-ligne-de-commande j'utilise les regex pour renommer des photos en ligne de commande sous linux :
rename 's/^([0-9]{8})_DSC56([0-9]{2})\.JPG/$1_$2_escalade.JPG/' *.JPG
^([0-9]{8})
veut dire que le nom du fichier doit commencer ^ par 8 caractères {8} correspondant à des chiffres [0-9] et grace au parenthèses qui entoure cette expression que ce sous-ensemble pourra être réutilisé par $1
suit une partie de chaîne invariable _DSC56 puis 2 caractères {2} correspondant à des chiffres [0-9], sous-ensemble réutilisé par $2
Attention ! la chaîne de recherche/remplacement doit être entre simple quote et non double.
Pour rechercher sélectionner des fichiers, sous gnu/linux (ubuntu en l'occurence), on peut lister certains fichiers :
ls | grep -E ^DSCN119[789]{1}.JPG
la commande ci-dessus liste les fichiers commençant par DSCN119 suivit du chiffre 7, 8 ou 9 suivi de .JPG
Nettoyer ou réordonner du code avec les REGEX
pour supprimer :
- les lignes en double (pas que les lignes vides!), rechercher
^(.*)(\r?\n\1)+$
et remplacer par$1
- les lignes vides, rechercher
^[\t]*[\r\n]+
et remplacer par rien. Sous vim, cela donne:g^\s*$/d
- les lignes vides répétées : comme ci-dessus en ajoutant la quantité :
^[\t]*[\r\n]{2,8}
à remplacer par\n
sous linux et\r\n
(sous windows) - les espaces et tabulations en fin de ligne, rechercher
[\t]*$
et remplacer par rien
pour reprendre-améliorer l'écriture du code (correction syntaxique) :
- espacer les affectations toto=1 --> toto = 1
([a-zA-Z\]0-9])=([a-zA-Z\-\(0-9'"])
ou(\w)=(\w|-)
remplacé par$1 = $2
On peut faire de même pour ajouter l'espace après une virgule, séparer les opérandes des opérateurs...
- Il est à noter qu'il est possible d'utiliser l'opérateur "ou" via la barre verticale | (à ne pas confondre avec le pipe de la ligne de commande) et ainsi multiplier encore les possibilités ... notamment de contrôle de chaînes ou de correction. Ainsi pour prendre en compte =, !=, ==, < et > :
(\w|\))(=|!=|==|<|>|<=|>=)(\w|-)
à remplacer par $1 $2 $3
mais aussi pour une recherche "simple" : recherche de toutes les déclarations de chaînes de caractère du type char * variable
ou char variable[80]
dans un vieux code: char\s*\* | char\s*\w+\[\d+\]
. Pour espacer autour des affectation + et - sans risquer de modifier les ++ et ->: (\w)(\+|\-)(\d)
à remplacer par $1 $2 $3
- déplacer l'accolade de début de fonction :
\)\t*\n\{
remplacé par\) {\n
(ajouter \r devant \n sous windows)
mafonction::maclasse (type arg)
{ type toto
devient ...
mafonction::maclasse (type arg) {
type toto
variante s'il y a un commentaire : \)\s+(//.+)\r\n\{
remplacé par \) \{ $1\r\n
- idemn repositionnement des accolades avec les if/else, case :
(\)|else|:)\s*(|//.*)\r\n\s+\{[ ]*(.*)\r\n
remplacé par$1 \{ $2\r\n\t$3\r\n
- remplacer 2 points de début de ligne par une tabulation :
^[ ]{2}
à remplacer par\t
puis on peut ré-itérer avec^\t[ ]{1}
,[ ]{1}\t
etc. - pour séparer des instructions sur une même ligne :
^(\t*)(.*);[ ]*(.+);$
remplacé par$1$2;\r\n$1$3;
- renommage des en-têtes pour respecter les règles Doxygen : renommage du nom du fichier:
(//|/\*)\s+([a-zA-Z0-9\._]+)(\.CPP|\.H).*
par\t\\file $2$3
. - puis modification de la première ligne :
.*(\r\n\t\\file)
par/\*!$1
. - puis récupération d'une éventuelle description qu'on bascule en \brief :
(\\file.*\r\n)(//|/\*).*\r\n(//|/\*)\s*([a-zA-Z0-9\._ ]+).*
par$1\t\\brief $4
. - puis modification de l'auteur initiale avec la date de création (adapter P.Nom par celui réél):
(//|/\*)\s*(P.Nom).\D+([0-9]{1,2}/[0-9]{1,2}/[0-9]{2}).*
par\t\\date de création $3\r\n\t\\author $2
.
Refactorer du code avec les REGEX
Lorsqu'on reprend un code ancien pour le mettre à niveau, il peut être très intéressant d'utiliser les regex pour transformer (ici avec vim) :
En C++
- Passer des char* en string:
- Passer les strcpy sur char* en = sur string:
%s/strcpy(\([a-zA-Z0-9_\-\]\[]\+\), \(".*"\)|\([a-zA-Z0-9_\-\[\]()]\+\))/\1 = \2/gc
le terme de droite peut être une constante "ma chaine" ou une variable (voire tableau) ou une fonction- ce qui convertit :
strcpy(file_out, file);
parfile_out = file;
- ce qui convertit :
Ajouter du code avec les REGEX
- ajouter des tests ou la gestion des exceptions (ici en C/C++) :
(\s*)(.*)\s*=\s*new\s*([a-zA-Z0-9_\->\"\', \(\)]{1,70});\s*//(.*)
qui décrit par exemple monPtr = new maClass(param1, ptr->maStruct); // mon commentaire
à remplacer par $1$2\t=\tnew $3;\t//$4$1if \($2 == NULL\) ::MessageBox\(NULL, "Erreur allocation mémoire sur $2", "Erreur", MB_OK\);
ce qui ajoute la ligne if (monPtr == NULL) ::MessageBox(NULL, "Erreur allocation mémoire sur monPtr ", "Erreur", MB_OK);
Caractères spéciaux avec les REGEX
Il est possible de manipuler des caractères spéciaux, il "suffit" d'échapper leur valeurs héxadécimale \x06
. Attention au charset utilisé et pensez bien, si vous avez la valeur en décimale, de la convertir en héxadécimal !