Expressions régulières
Anatomie
Une expression régulière est composée d'éléments aux rôles bien définis :
/motif/flags — La notation standard. Les barres obliques / servent de délimiteurs ; les flags contrôlent le comportement global : g (toutes les correspondances), i (insensible à la casse), m (^/$ par ligne), s (. inclut les sauts de ligne).
Métacaractères — Symboles à signification spéciale : . (tout caractère sauf \n), \d (un chiffre), \w (lettre, chiffre ou _), \s (espace blanc). Leurs négations : \D, \W, \S.
Quantificateurs — Répétitions : * (0 ou plus), + (1 ou plus), ? (0 ou 1), {n} (exactement n), {n,m} (entre n et m). Par défaut ils sont greedy ; ajouter ? les rend lazy.
Ancres — Positions sans consommer de caractères : ^ (début), $ (fin), \b (frontière de mot).
Classes de caractères — [abc] correspond à a, b ou c. [a-z] est une plage. [^abc] est la négation.
Groupes — (...) groupe et capture. (?:...) groupe sans capturer. (?<nom>...) crée des captures nommées. (?=...) et (?!...) sont des lookaheads.
Alternance — chat|chien correspond à "chat" ou "chien".
Histoire et évolution
La théorie mathématique qui sous-tend les expressions régulières a été formalisée par le mathématicien Stephen Kleene en 1956. Le passage de la théorie à la pratique a été réalisé par Ken Thompson en 1968, en implémentant les regex dans l'éditeur ed d'UNIX. En 1973, il a créé grep — outil emblématique d'UNIX — dont le nom vient de la syntaxe regex : g/re/p (global regular expression print).
Dans les années 1980, POSIX a standardisé les BRE et ERE, encore utilisées dans grep, sed et awk. Le tournant fondamental est arrivé en 1987, quand Larry Wall a conçu Perl avec les regex comme élément central, créant les PCRE (Perl Compatible Regular Expressions), standard de facto adopté par PHP, Python, Ruby, Java et JavaScript.
En 1997, Philip Hazel a publié la bibliothèque PCRE en tant qu'implémentation indépendante. Aujourd'hui les PCRE2 sont présentes dans Apache, Nginx, PostgreSQL et pratiquement tous les outils du monde numérique.
Bonnes pratiques
Testez toujours avec des données réelles et des cas limites. Une regex valide pour 3 exemples peut échouer avec des données réelles inattendues.
Ancrez quand c'est possible. Utiliser ^ et $ réduit le temps de recherche et évite les correspondances partielles non prévues.
Évitez le backtracking catastrophique. Des motifs comme (a+)+ peuvent prendre un temps exponentiel et bloquer un serveur (ReDoS).
Utilisez les groupes non capturants (?:...) par défaut. Si vous n'avez pas besoin de la capture, (?:...) est plus efficace et indique clairement que le groupe est structurel.
Commentez les regex complexes. En Python et PHP, le flag (?x) (verbose mode) permet d'ajouter des espaces et des commentaires dans le motif.
Erreurs courantes
Oublier d'échapper le point. . signifie "n'importe quel caractère", pas un point littéral. Écrivez \. pour un point littéral.
Greedy vs lazy mal appliqué. <.*> sur <b>texte</b> capture tout le fragment. La version lazy <.*?> capture chaque balise individuellement.
Oublier le flag g. Sans g, string.match(/motif/) en JavaScript ne retourne que la première correspondance.
Backtracking catastrophique. Le motif (a+)+b peut prendre un temps exponentiel sur des chaînes sans correspondance. Exploitable pour bloquer des services (ReDoS).
Supposer que . inclut les sauts de ligne. Par défaut non. Utilisez le flag s ou [\s\S].
Utiliser les regex pour HTML ou JSON. C'est un antipattern : fragile face à l'imbrication. Utilisez des parsers spécialisés.
Cas d'utilisation
Validation de formulaires. E-mails, numéros de téléphone, codes postaux : les regex valident le format côté client et serveur simultanément.
Analyse de logs. Avec les regex, vous pouvez extraire des IP, codes HTTP, horodatages ou erreurs spécifiques de millions de lignes en quelques secondes.
Find & replace avancé. VS Code, Vim et Sublime Text supportent les regex en recherche/remplacement. Renommez 500 variables ou reformatez des dates dans un CSV de 100 000 lignes en une seule opération.
Routage dans les frameworks web. Rails, Laravel, Django et Express définissent leurs routes avec des motifs qui capturent les paramètres d'URL.
Traitement de données et ETL. Les regex extraient des champs de formats non structurés pour les normaliser et les charger dans des bases de données.
Curiosités
- Le nom grep vient de la commande <code>:g/re/p</code> de l'éditeur <code>ed</code> d'UNIX (1973) : "global regular expression print". Sa création par Ken Thompson a mis les regex à la portée de tout utilisateur UNIX.
- Le phénomène ReDoS (Regular Expression Denial of Service) a causé de vraies pannes : en 2016, une regex avec backtracking catastrophique a mis Stack Overflow hors service pendant 34 minutes en production.
- La RFC 5322, norme formelle des adresses e-mail, peut être entièrement validée par une regex, mais celle-ci fait 6 318 caractères. Pour un usage pratique, une regex de 50 à 100 caractères couvre 99,9 % des cas réels.
- XKCD a publié le comic #208 "Regular Expressions" en 2007. C'est la référence culturelle centrale de la communauté des développeurs pour parler de regex.