Par où commencer pour bien comprendre les expressions régulières ?
Vous souhaitez mettre votre solution en avant en haut de cet article ? Contactez-nous
Aujourd'hui le BlogDuWebdesign demystifie pour vous un domaine particulièrement complexe au premier abord et finalement plus simple qu'on le croit : les expressions régulières
Les expressions régulières sont sans doute un des domaines les plus cryptiques que l'on puisse trouver en programmation (avec le Brainfuck. Si vous ne connaissez pas, allez jeter un oeil juste pour rigoler, ça fait une bonne anecdote en repas de familles).
A quoi servent les expressions régulières
Les expressions régulières sont un moyen de représenter une ou plusieurs chaines de textes.
Elles servent en collaboration avec d'autres outils à détecter des mails dans une page, cibler simplement des erreurs dans un fichier de log, mais aussi de manière plus courante à faire de chercher remplacer très puissants dans votre éditeur de texte, ou tout simplement automatiser en quelques minutes une tache que vous pourriez passer plusieurs heures à faire.
Les expressions régulières ont juste une quantité d'usages presque infini pour tout ce qui touche au texte, et si vous êtes un intégrateur ou un développeur et que vous passez donc la plupart de vos journées dans un éditeur de texte, c'est sans doute une des compétences les plus intéressantes pour vous à obtenir.
Et puis ça permet de se la jouer superhéros quand des collègues ne connaissent pas et en ont un besoin vital, aussi.
La mauvaise image des expressions régulières
Prenons un exemple tiré de faits réels (je suis sur que beaucoup d'entre vous se reconnaîtront) : un développeur a besoin de valider qu'une valeur texte est un email. Il cherche un petit peu comment s'en sortir, puis quelqu'un passe derrière lui et lui dit : "Pourquoi est-ce que tu n'utilises pas une expression régulière ? Attends, je t'en écrit une pour matcher les emails".
/^[-a-z0-9~!$%^&*_=+}{'?]+(.[-a-z0-9~!$%^&*_=+}{'?]+)*@([a-z0-9_][-a-z0-9_]*(.[-a-z0-9_]+)*.(aero|arpa|biz|com|coop|edu|gov|info|int|mil|museum|name|net|org|pro|travel|mobi|[a-z][a-z])|([0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}))(:[0-9]{1,5})?$/i
"Voilà, avec ça va marcher !". Et effectivement, ça marche, mais pourquoi ? Plus notre développeur regarde cette ligne, moins il semble la comprendre. Bien sur, il y a quelques trucs qu'il arrive à deviner, mais la logique ne suit pas (aero, museum, net et autres semblent être des extensions de domaines, mais fr n'est pas dedans, pourtant il marche, …). Il en conclut donc que les Regexp se sont pratique mais que c'est quand même bien trop compliqué pour les services rendus, et lâche l'affaire.
Comprendre les expressions régulières
Avant tout, je tiens à dire qu'il ne faut pas avoir peur des expressions régulières. Elles semblent cryptiques, mais si vous avez déjà des bases en intégration, développement ou si vous avez déjà touché aux formules d'un tableau (Excel par exemple) vous avez déjà vu pire dans votre vie.
Il faut comprendre que les expressions régulières ne sont finalement qu'une sorte de langage basique permettant de décrire des chaines de textes et de les représenter. La plupart des expressions régulières peuvent représenter plusieurs chaines, c'est même le but de la manoeuvre !
Une fois que vous aurez quelques "mots de vocabulaire", il vous sera possible de détricoter progressivement toute une regexp et donc la comprendre. Prenons l'exemple suivant et essayons de découper chacun des éléments reconnaissables de cette expression régulière.
Pour commencer, notez qu'elle commence par "/" et finit par "/i". Comme pour les chaines de textes sont entourées de quotes, ou comme les déclarations CSS doivent être contenu entre "{}", les expressions régulières doivent être entourées par des slashs par principe.
Le "i" qui traine à la fin est un flag. C'est une sorte d'informations supplémentaires qui modifie tout le reste de l'expression. "i" signifie "insensible à la casse", ce qui veut dire que notre expression régulière ne fera aucun cas des majuscules et minuscules, "a" et "A" seront donc identiques pour elles.
Ensuite, intéressons-nous au mot "bonjour", qui sert à détecter… le mot bonjour? La plupart des caractères se représentent eux-mêmes, et servent donc à détecter la présence de ce caractère dans une chaine. De la même manière, l'espace " " après le "bonjour" n'est pas innocent, il sert lui aussi à représenter un espace.
Plus compliqué maintenant : [a-z-].
Le groupe "[]" représente une classe de caractère. Il peut signifier n'importe lequel des caractères le comprenant. [abc] représenterait donc par exemple "à", "b" ou bien "c".
a-z est un intervalle, et signifie "tous les caractères entrer "à" et "z", donc toutes les lettres de l'alphabet. Ils ne sont utilisables que dans les classes de caractères.
– est un "-" qui a été "protegé" par un backslash. Comme nous l'avons vu juste au-dessus, le "-" sert à déterminer un intervalle, nous ne pouvons donc pas l'utiliser pour se représenter lui-même dans une classe. La solution est de le protéger (on dit "échapper") en le précédant d'un backslash. "-" Représente donc un tiret.
En conclusion, notre groupe [a-z-] représente n'importe quel caractère entré à et z ou bien un tiret. À cause du flag "i", notre groupe représente aussi les caractères majuscules. Il aurait été possible de l'écrire sans le flag de cette manière : : [a-zA-Z-]
Enfin, le dernier caractère à examiner est le "+". Notre objectif, vous l'aurez surement compris maintenant, est de représenter une chaine comme par exemple "bonjour Benjamin". Or, une classe de caractère ne représente qu'un seul caractère. Nous pourrions bien sur copier coller 8 fois d'affilée notre classe de caractère, mais non seulement cela serait fastidieux, nous ne pourrions capturer que les prénoms contenant 8 caractères exactement. Ce plus sont la solution à ce problème
Le "+" signifie que le caractère ou la classe précédente peut être présent entre une et une infinite de fois. De cette manière, nous pourrons aussi bien capturer "Bonjour Benjamin" que "Bonjour Alexis", alors que le nombre de lettres ne correspond pas.
La suite
Il y a tellement de choses à dire sur les expressions régulières ! Lister les flags et leurs effets, vous parlez des caractères "*" et "?", vous montrez les classes de caractères inverses [^abc], … Je pourrais y passer la journée. Je vais pourtant m'arrêter là, pour ne pas vous perdre. Si vous n'avez à retenir que deux choses de cet article, cela doit être "une expression régulière est un schéma permettant de représenter et décrire une chaine de caractères", et "une expression régulière n'est qu'une somme de petites expressions simples a comprendre pris séparément."
Si vous avez envie d'aller plus loin, je vous conseille vraiment de chercher à lire et comprendre des expressions régulières, c'est comme ça que vous apprendrez et surtout retiendrez le mieux la signification des différents symboles. Pour vous aider, je vous conseille aussi d'aller sur le site "regexr.com", qui vous fournira des explications et une représentation graphique sur vos expressions régulières.