🛠 Outils IT
🛠 78 outils 📚 32 docs
🤖 Assistant

Regex (Expressions regulieres)

1. Introduction

1.1 Qu'est-ce qu'une expression reguliere ?

Une expression reguliere (ou regex, abreviation de regular expression) est une sequence de caracteres qui definit un motif de recherche (pattern). Ce motif permet de decrire un ensemble de chaines de caracteres possibles selon des regles precises.

En d'autres termes, une regex est un mini-langage de description de texte. Au lieu de chercher un mot exact, on decrit la forme de ce qu'on cherche.

1.2 A quoi ca sert ?

  • Rechercher du texte correspondant a un motif precis dans une chaine ou un fichier
  • Valider des formats de donnees (email, telephone, code postal, URL, etc.)
  • Extraire des parties specifiques d'un texte (groupes de capture)
  • Remplacer du texte selon un motif (rechercher-remplacer avance)
  • Decouper une chaine en sous-elements (split)
  • Filtrer des lignes dans des fichiers de log, CSV, etc.

1.3 Exemple rapide

Imaginons qu'on veut verifier si une chaine ressemble a une adresse email :

# Au lieu de verifier caractere par caractere...
# On utilise une regex :
/^[\w.+-]+@[\w-]+\.[\w.]+$/

# Ce motif decrit :
# ^          : debut de la chaine
# [\w.+-]+   : un ou plusieurs caracteres alphanumeriques, points, +, -
# @          : le symbole arobase (litteral)
# [\w-]+     : un ou plusieurs caracteres alphanumeriques ou tirets
# \.         : un point (litteral, echappe avec \)
# [\w.]+     : un ou plusieurs caracteres alphanumeriques ou points
# $          : fin de la chaine
Astuce : Pour tester vos regex en temps reel, utilisez des outils en ligne comme regex101.com (supporte PCRE, JavaScript, Python, Go) ou regexr.com. Ces outils montrent les correspondances en temps reel et expliquent chaque partie du motif.

2. Caracteres speciaux (Metacaracteres)

Les metacaracteres sont des caracteres ayant une signification speciale dans les expressions regulieres. Pour les utiliser comme caracteres litteraux, il faut les echapper avec un antislash (\).

Caractere Description Exemple Correspond a
. N'importe quel caractere (sauf \n par defaut) a.c abc, a1c, a-c, a c
^ Debut de la chaine (ou de la ligne avec flag m) ^Bonjour Bonjour en debut de chaine
$ Fin de la chaine (ou de la ligne avec flag m) fin$ fin en fin de chaine
* Zero ou plusieurs occurrences du caractere precedent ab*c ac, abc, abbc, abbbc
+ Une ou plusieurs occurrences du caractere precedent ab+c abc, abbc, abbbc (pas ac)
? Zero ou une occurrence du caractere precedent (optionnel) colou?r color, colour
{n} Exactement n occurrences a{3} aaa
{n,m} Entre n et m occurrences a{2,4} aa, aaa, aaaa
[] Classe de caracteres (un parmi ceux listes) [aeiou] a, e, i, o, u
() Groupe de capture (abc)+ abc, abcabc
| Alternance (OU logique) chat|chien chat ou chien
\ Echappement (rend le metacaractere litteral) \. Le caractere point . litteral
Astuce : Pour echapper un caractere special et le traiter comme litteral, placez un \ devant. Par exemple, pour chercher le prix 9.99$, ecrivez 9\.99\$. Les caracteres a echapper sont : . ^ $ * + ? { } [ ] ( ) | \

3. Classes de caracteres

Les classes de caracteres permettent de definir un ensemble de caracteres possibles pour une position donnee. Les raccourcis (\d, \w, \s) simplifient l'ecriture.

3.1 Raccourcis predefinies

Classe Equivalent Description Exemple Correspond a
\d [0-9] Un chiffre \d{3} 123, 007, 999
\D [^0-9] Tout sauf un chiffre \D+ abc, ---,
\w [a-zA-Z0-9_] Caractere de mot (lettre, chiffre, underscore) \w+ hello, var_1, test42
\W [^a-zA-Z0-9_] Tout sauf un caractere de mot \W , @, !, -
\s [ \t\n\r\f\v] Espace blanc (espace, tab, retour a la ligne) \s+ espaces, tabulations, sauts de ligne
\S [^ \t\n\r\f\v] Tout sauf un espace blanc \S+ tout mot/texte sans espace

3.2 Classes personnalisees avec crochets

Pattern Description Exemple
[abc] Un caractere parmi a, b ou c [aeiou] correspond a n'importe quelle voyelle
[a-z] Une lettre minuscule de a a z [a-z]+ correspond a hello
[A-Z] Une lettre majuscule de A a Z [A-Z]{2} correspond a FR, US
[0-9] Un chiffre de 0 a 9 [0-9]{5} correspond a 75001
[a-zA-Z] N'importe quelle lettre (majuscule ou minuscule) [a-zA-Z]+ correspond a Bonjour
[a-zA-Z0-9] Lettre ou chiffre (alphanumerique) [a-zA-Z0-9]+ correspond a abc123
[^abc] N'importe quel caractere sauf a, b ou c (negation) [^0-9] correspond a tout sauf un chiffre
[a-z&&[^aeiou]] Consonnes uniquement (Java seulement) Intersection de classes (support variable)

3.3 Caracteres speciaux dans les crochets

A l'interieur des crochets [], la plupart des metacaracteres perdent leur sens special. Les exceptions :

# Le tiret - definit une plage (sauf en debut ou fin)
[a-z]        # plage de a a z
[-az]        # litteral : tiret, a ou z  (tiret en debut)
[az-]        # litteral : a, z ou tiret  (tiret en fin)

# Le chapeau ^ en premiere position = negation
[^abc]       # tout sauf a, b, c
[a^bc]       # a, ^, b ou c  (litteral car pas en premiere position)

# Le crochet fermant ] doit etre en premiere position ou echappe
[]abc]       # ], a, b ou c
[abc\]]      # a, b, c ou ]

# L'antislash \ garde son role d'echappement
[\d\s]       # un chiffre ou un espace
[\\]         # un antislash litteral
Astuce : La notation \d est un raccourci pour [0-9], mais attention : dans certaines implementations (ex. Python avec le flag Unicode), \d peut aussi correspondre a des chiffres non-ASCII (chiffres arabes, devanagari, etc.). En cas de doute, utilisez [0-9] pour restreindre aux chiffres ASCII.

4. Quantificateurs

Les quantificateurs indiquent combien de fois l'element precedent peut se repeter.

4.1 Reference des quantificateurs

Quantificateur Description Exemple Correspond a
* 0 ou plusieurs (zero ou plus) ab*c ac, abc, abbc, abbbc...
+ 1 ou plusieurs (un ou plus) ab+c abc, abbc, abbbc... (pas ac)
? 0 ou 1 (optionnel) https? http, https
{n} Exactement n fois \d{4} 2024, 1234, 0000
{n,} Au moins n fois (n ou plus) \d{2,} 12, 123, 1234567...
{n,m} Entre n et m fois (inclus) \d{2,4} 12, 123, 1234
{0,m} Au maximum m fois a{0,3} (vide), a, aa, aaa

4.2 Greedy vs Lazy (Gourmand vs Paresseux)

Par defaut, les quantificateurs sont gourmands (greedy) : ils capturent le maximum de caracteres possible. En ajoutant ? apres le quantificateur, il devient paresseux (lazy) et capture le minimum.

Greedy (gourmand) Lazy (paresseux) Description
* *? 0 ou plus, mais le moins possible
+ +? 1 ou plus, mais le moins possible
? ?? 0 ou 1, mais prefere 0
{n,m} {n,m}? Entre n et m, mais le moins possible
# Exemple concret : extraire le contenu d'une balise HTML
# Texte : <b>gras</b> et <b>aussi gras</b>

# GREEDY (gourmand) - <b>.*</b>
# Resultat : <b>gras</b> et <b>aussi gras</b>
# (capture TOUT entre le premier <b> et le DERNIER </b>)

# LAZY (paresseux) - <b>.*?</b>
# Resultat : <b>gras</b>  puis  <b>aussi gras</b>
# (capture le MINIMUM entre chaque paire <b>...</b>)
Attention : La difference entre greedy et lazy est cruciale lorsqu'on travaille avec du HTML ou des textes contenant des delimiteurs repetes. Utilisez toujours le mode lazy (*?, +?) quand vous voulez capturer la correspondance la plus courte possible.

5. Ancres et limites

Les ancres ne correspondent a aucun caractere : elles indiquent une position dans la chaine.

5.1 Ancres de base

Ancre Description Exemple Explication
^ Debut de la chaine (ou de la ligne avec flag m) ^Bonjour Correspond seulement si "Bonjour" est au debut
$ Fin de la chaine (ou de la ligne avec flag m) monde$ Correspond seulement si "monde" est a la fin
\b Limite de mot (entre un \w et un \W) \bchat\b Correspond a "chat" mais pas a "chaton" ni "rachat"
\B Pas une limite de mot (inverse de \b) \Bchat\B Correspond a "chat" dans "rachats" mais pas au mot "chat" seul
# Exemples pratiques avec \b (limite de mot)
\bweb\b       # "web" comme mot complet
                # OUI : "le web est", "web design"
                # NON : "cobweb", "website", "webinar"

\bpre          # mots commencant par "pre"
                # OUI : "premier", "prevenir", "precis"

tion\b         # mots finissant par "tion"
                # OUI : "action", "station", "creation"

# Exemples avec ^ et $
^$             # ligne vide (rien entre le debut et la fin)
^.+$           # ligne non vide (au moins un caractere)
^\s*$          # ligne vide ou contenant uniquement des espaces

5.2 Lookahead (assertion avant)

Les lookahead verifient ce qui suit la position actuelle sans le consommer (la position ne bouge pas).

Syntaxe Nom Description Exemple Resultat
(?=...) Lookahead positif Ce qui suit doit correspondre \d+(?= euros) Capture 100 dans "100 euros" mais pas dans "100 dollars"
(?!...) Lookahead negatif Ce qui suit ne doit PAS correspondre \d+(?! euros) Capture 100 dans "100 dollars" mais pas dans "100 euros"

5.3 Lookbehind (assertion arriere)

Les lookbehind verifient ce qui precede la position actuelle sans le consommer.

Syntaxe Nom Description Exemple Resultat
(?<=...) Lookbehind positif Ce qui precede doit correspondre (?<=\$)\d+ Capture 50 dans "$50" mais pas dans "50"
(?<!...) Lookbehind negatif Ce qui precede ne doit PAS correspondre (?<!\$)\d+ Capture 50 dans "50 items" mais pas dans "$50"
# Exemples pratiques de lookahead / lookbehind

# Trouver des montants en euros (nombre suivi de "EUR" ou "euros")
\d+(?:\.\d{2})?(?=\s*(?:EUR|euros?))
# Correspond a : "150.00 EUR", "42 euros", "9.99 euro"

# Extraire le prix sans le symbole dollar
(?<=\$)\d+(?:\.\d{2})?
# Dans "$19.99 et $5.00" : capture "19.99" et "5.00"

# Mot suivi d'un point mais sans capturer le point
\w+(?=\.)
# Dans "fin. suite" : capture "fin"

# Mot de passe : verifier qu'il contient au moins un chiffre et une majuscule
# (utilisation de lookahead multiples)
^(?=.*[A-Z])(?=.*\d).{8,}$
# Valide : "Passw0rd", "Test1234"
# Invalide : "password", "12345678"
Note : Les lookbehind ont des limitations variables selon les moteurs regex :
  • JavaScript : lookbehind supporte depuis ES2018 (longueur variable autorisee)
  • PHP (PCRE) : lookbehind doit avoir une longueur fixe (pas de * ou +)
  • Python : lookbehind doit avoir une longueur fixe
  • Java : lookbehind a longueur variable limitee (pas de quantificateurs illimites)

6. Groupes et captures

Les groupes permettent de regrouper des elements, d'appliquer des quantificateurs sur des sous-expressions et d'extraire des parties du texte.

6.1 Types de groupes

Syntaxe Nom Description Exemple
(...) Groupe de capture Capture le contenu pour reutilisation (ab)+ capture "ab", "abab"
(?:...) Groupe non-capturant Regroupe sans capturer (meilleure performance) (?:ab)+ meme effet sans capture
(?P<nom>...) Groupe nomme (PHP/Python) Capture avec un nom (plus lisible) (?P<annee>\d{4})
(?<nom>...) Groupe nomme (JS/Java/.NET) Capture avec un nom (syntaxe alternative) (?<year>\d{4})
(?=...) Lookahead positif Verifie sans consommer (voir section 5) foo(?=bar)
(?!...) Lookahead negatif Verifie l'absence sans consommer foo(?!bar)
(?<=...) Lookbehind positif Verifie ce qui precede sans consommer (?<=@)\w+
(?<!...) Lookbehind negatif Verifie l'absence en arriere (?<!un)chat

6.2 References arriere (Back-references)

Les back-references permettent de faire reference a un groupe deja capture plus tot dans la meme regex. Utile pour trouver des repetitions ou des correspondances symetriques.

Syntaxe Description Exemple Correspond a
\1, \2, ... Reference au groupe N (par numero) (mot)\s+\1 "mot mot" (mot repete)
\k<nom> Reference a un groupe nomme (?<tag>\w+).*\k<tag> Balises appairees
# Trouver les mots repetes (doublons)
\b(\w+)\s+\1\b
# Trouve : "le le", "est est", "the the"
# Texte : "Il est est parti" -> correspond a "est est"

# Trouver les balises HTML ouvrantes et fermantes appairees
<(\w+)[^>]*>.*?</\1>
# Trouve : <div>contenu</div>, <p>texte</p>
# Ne trouve PAS : <div>contenu</p> (balises differentes)

# Extraire une date au format JJ/MM/AAAA en groupes
(\d{2})/(\d{2})/(\d{4})
# Sur "25/12/2024" :
#   Groupe 1 (\1) = "25"  (jour)
#   Groupe 2 (\2) = "12"  (mois)
#   Groupe 3 (\3) = "2024" (annee)

# Reformater une date de JJ/MM/AAAA vers AAAA-MM-JJ (en remplacement)
# Recherche :  (\d{2})/(\d{2})/(\d{4})
# Remplacement : $3-$2-$1  (ou \3-\2-\1 selon le langage)
# "25/12/2024" -> "2024-12-25"

# Groupe nomme : extraire des parties d'une URL
(?P<protocole>https?):\/\/(?P<domaine>[\w.-]+)(?::(?P<port>\d+))?(?P<chemin>\/\S*)?
# Sur "https://example.com:8080/page?id=1" :
#   protocole = "https"
#   domaine   = "example.com"
#   port      = "8080"
#   chemin    = "/page?id=1"
Astuce : Utilisez les groupes non-capturants (?:...) quand vous avez besoin de regrouper pour appliquer un quantificateur mais que vous n'avez pas besoin de capturer le contenu. Cela ameliore legerement les performances et garde la numerotation des groupes propre.

7. Drapeaux (Flags)

Les drapeaux modifient le comportement global du moteur regex. Ils s'ajoutent generalement apres le delimiteur de fin du pattern.

Flag Nom Description Exemple
g Global Trouver toutes les correspondances (pas seulement la premiere) /abc/g trouve tous les "abc" dans le texte
i Insensible a la casse Ignore la difference majuscules/minuscules /bonjour/i trouve "Bonjour", "BONJOUR", "bonjour"
m Multiligne ^ et $ correspondent au debut/fin de chaque ligne (pas seulement la chaine entiere) /^ligne/m trouve "ligne" au debut de chaque ligne
s Dotall (single line) Le point . correspond aussi aux sauts de ligne \n /debut.*fin/s traverse les lignes
u Unicode Traite le pattern et le texte en UTF-8 / mode Unicode complet /\w+/u comprend les caracteres accentues
x Verbose / etendu Ignore les espaces et autorise les commentaires # dans le pattern Permet d'ecrire des regex lisibles sur plusieurs lignes
# Syntaxe des drapeaux selon le langage

# JavaScript : /pattern/flags
let regex = /bonjour/gi;         // global + insensible a la casse

# PHP : "delimiteur pattern delimiteur flags"
$regex = '/bonjour/giu';         // global + insensible + unicode

# Python : re.compile(pattern, flags)
import re
regex = re.compile(r'bonjour', re.IGNORECASE | re.MULTILINE)

# Exemple avec le flag x (verbose) en PHP/Python :
$regex = '/
    ^                   # debut de la chaine
    [\w.+-]+            # partie locale de l email
    @                   # arobase
    [\w-]+              # nom de domaine
    \.                  # point
    [a-zA-Z]{2,}        # extension (TLD)
    $                   # fin de la chaine
/x';
# Equivalent compact : /^[\w.+-]+@[\w-]+\.[a-zA-Z]{2,}$/
Astuce : Le flag x (verbose/etendu) est extremement utile pour les regex complexes. Il permet d'ajouter des espaces et des commentaires, rendant le pattern beaucoup plus lisible et maintenable. Utilisez-le systematiquement pour les regex de plus de 30 caracteres.

8. Exemples pratiques courants

Voici une collection complete de patterns regex pour les cas d'utilisation les plus frequents. Chaque pattern est fourni avec des exemples de chaines valides et invalides.

8.1 Adresse email

# Validation basique d'email
^[\w.+-]+@[\w-]+\.[\w.]+$

# Validation plus stricte (RFC 5322 simplifiee)
^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$

# Exemples valides : user@example.com, prenom.nom@societe.fr, test+tag@mail.co.uk
# Exemples invalides : @example.com, user@, user@.com, user@com

8.2 Numero de telephone francais

# Format national : 01 23 45 67 89 ou 0123456789
^0[1-9](?:[\s.-]?\d{2}){4}$

# Format international : +33 1 23 45 67 89 ou +33123456789
^(?:\+33|0033|0)[1-9](?:[\s.-]?\d{2}){4}$

# Telephone mobile uniquement (06 et 07)
^(?:\+33|0033|0)[67](?:[\s.-]?\d{2}){4}$

# Exemples valides : 01 23 45 67 89, 06.12.34.56.78, +33 6 12 34 56 78, 0612345678
# Exemples invalides : 00 12 34 56 78, 1234567890, +33 0 12 34 56 78

8.3 Code postal francais

# Code postal francais (5 chiffres, departements 01 a 98 + DOM-TOM)
^(?:0[1-9]|[1-8]\d|9[0-8])\d{3}$

# Avec les DOM-TOM (97x, 98x)
^(?:0[1-9]|[1-8]\d|9[0-8]|97[1-6]|98[4-8])\d{2,3}$

# Version simple (5 chiffres commencant par 01-98)
^\d{5}$

# Exemples valides : 75001, 13100, 97400, 69001
# Exemples invalides : 00123, 99999, 7500, 750012

8.4 Adresse IP (IPv4)

# IPv4 stricte (0-255 par octet)
^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$

# IPv4 simple (moins stricte mais plus lisible)
^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$

# IPv4 avec masque CIDR
^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\/(?:3[0-2]|[12]?\d)$

# Exemples valides : 192.168.1.1, 10.0.0.0, 255.255.255.0, 172.16.0.1/24
# Exemples invalides : 256.1.1.1, 192.168.1, 10.0.0.0.1

8.5 URL

# URL HTTP/HTTPS
^https?:\/\/(?:[\w-]+\.)+[a-zA-Z]{2,}(?::\d{1,5})?(?:\/[^\s]*)?$

# URL plus complete (avec parametres et ancre)
^https?:\/\/(?:www\.)?[\w-]+(?:\.[\w-]+)+(?::\d{1,5})?(?:\/[\w.~:/?#\[\]@!$&'()*+,;=-]*)?$

# Exemples valides : https://example.com, http://www.site.fr/page?id=1#section
# Exemples invalides : ftp://server.com, example.com (manque le protocole)

8.6 Date au format JJ/MM/AAAA

# Date JJ/MM/AAAA (validation basique)
^(0[1-9]|[12]\d|3[01])\/(0[1-9]|1[0-2])\/\d{4}$

# Date avec separateur flexible (/, - ou .)
^(0[1-9]|[12]\d|3[01])[\/\-\.](0[1-9]|1[0-2])[\/\-\.]\d{4}$

# Date AAAA-MM-JJ (format ISO 8601)
^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$

# Exemples valides : 25/12/2024, 01-01-2000, 2024-06-15
# Exemples invalides : 32/01/2024, 00/13/2024, 2024/1/1

8.7 Mot de passe fort

# Mot de passe fort : 8+ caracteres, 1 majuscule, 1 minuscule, 1 chiffre
^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$

# Mot de passe tres fort : 12+ car., majuscule, minuscule, chiffre, special
^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]).{12,}$

# Mot de passe sans espaces, 8-64 caracteres
^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[\W_])[^\s]{8,64}$

# Exemples valides : "Passw0rd!", "MonSuperMDP2024!", "C0mpl3x&Fort"
# Exemples invalides : "password", "12345678", "abcABC", "Short1!"

8.8 Nom de fichier

# Nom de fichier valide (lettres, chiffres, tirets, underscores, point pour extension)
^[\w\-]+\.\w{1,10}$

# Nom de fichier avec chemin (Unix)
^(?:\/[\w.\-]+)+$

# Nom de fichier avec chemin (Windows)
^[a-zA-Z]:\\(?:[\w.\-\s]+\\)*[\w.\-\s]+$

# Extension specifique (images)
^[\w\-]+\.(?:jpg|jpeg|png|gif|svg|webp|bmp)$

# Extension specifique (documents)
^[\w\-]+\.(?:pdf|doc|docx|xls|xlsx|ppt|pptx|txt|csv)$

# Exemples valides : rapport-2024.pdf, image_01.png, C:\Users\docs\file.txt
# Exemples invalides : fichier, ../hack.php, fichier<>.txt

8.9 Adresse MAC

# Adresse MAC (format XX:XX:XX:XX:XX:XX)
^([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}$

# Adresse MAC (format XX-XX-XX-XX-XX-XX)
^([0-9A-Fa-f]{2}-){5}[0-9A-Fa-f]{2}$

# Les deux formats
^([0-9A-Fa-f]{2}[:\-]){5}[0-9A-Fa-f]{2}$

# Format Cisco (XXXX.XXXX.XXXX)
^([0-9A-Fa-f]{4}\.){2}[0-9A-Fa-f]{4}$

# Exemples valides : 00:1A:2B:3C:4D:5E, 00-1a-2b-3c-4d-5e, 001A.2B3C.4D5E
# Exemples invalides : 00:1A:2B:3C:4D, GG:HH:II:JJ:KK:LL

8.10 Code IBAN

# IBAN generique (2 lettres pays + 2 chiffres controle + 10 a 30 alphanumeriques)
^[A-Z]{2}\d{2}[A-Z0-9]{10,30}$

# IBAN francais (27 caracteres : FR + 2 chiffres + 23 alphanumeriques)
^FR\d{2}[\dA-Z]{23}$

# IBAN francais avec espaces (format lisible)
^FR\d{2}(?:\s?\d{4}){5}\s?\d{3}$

# Exemples valides : FR7630001007941234567890185, FR76 3000 1007 9412 3456 7890 185
# Exemples invalides : FR123, XXFR7630001007941234567890185

8.11 Balises HTML

# Trouver une balise HTML ouvrante
<([a-zA-Z][\w-]*)(?:\s+[^>]*)?>

# Trouver une balise HTML fermante
<\/([a-zA-Z][\w-]*)>

# Trouver une balise complete avec son contenu (non-imbrique)
<(\w+)(?:\s+[^>]*)?>(.*?)<\/\1>

# Balises auto-fermantes
<(\w+)(?:\s+[^>]*)?\s*\/>

# Extraire les attributs d'une balise
(\w+)=["']([^"']*)["']

# Supprimer toutes les balises HTML (texte brut)
<[^>]+>

# Exemples :
# <div class="container">  -> balise ouvrante, classe="container"
# </div>                   -> balise fermante
# <img src="photo.jpg" />  -> balise auto-fermante
# <p>Texte</p>            -> balise complete

8.12 Espaces multiples et nettoyage

# Remplacer les espaces multiples par un seul espace
\s{2,}
# Remplacement : " " (un seul espace)
# "Hello    World" -> "Hello World"

# Supprimer les espaces en debut et fin de chaine (trim)
^\s+|\s+$
# Remplacement : "" (chaine vide)
# "  Hello World  " -> "Hello World"

# Supprimer les lignes vides
^\s*$\n?
# Remplacement : "" (avec flag m pour multiligne)

# Supprimer les espaces autour des virgules
\s*,\s*
# Remplacement : ", "
# "a ,b , c,  d" -> "a, b, c, d"

# Supprimer les espaces en debut de chaque ligne
^[ \t]+
# Avec flag m (multiligne)

8.13 Commentaires de code

# Commentaires monoligne C/JS/PHP (//)
\/\/.*$

# Commentaires multiligne C/JS/PHP (/* ... */)
\/\*[\s\S]*?\*\/

# Commentaires monoligne Python/Bash (#)
#.*$

# Commentaires HTML (<!-- ... -->)
<!--[\s\S]*?-->

# Tous les commentaires JS/PHP (mono + multi ligne)
\/\/.*$|\/\*[\s\S]*?\*\/

# Exemples :
# // Ceci est un commentaire    -> correspond
# /* Ceci est
#    un commentaire */           -> correspond
# # commentaire bash             -> correspond
# <!-- commentaire HTML -->     -> correspond

8.14 Nombres et montants

# Nombre entier (positif)
^\d+$

# Nombre entier (positif ou negatif)
^-?\d+$

# Nombre decimal (avec point ou virgule)
^-?\d+(?:[.,]\d+)?$

# Montant en euros (2 decimales obligatoires)
^\d+(?:\s?\d{3})*[.,]\d{2}$

# Montant avec separateur de milliers
^\d{1,3}(?:\s\d{3})*(?:[.,]\d{2})?$

# Nombre hexadecimal
^(?:0x)?[0-9A-Fa-f]+$

# Exemples valides : 42, -17, 3.14, 1 234,56, 0xFF
# Exemples invalides : 12.34.56, --5, 12,345.67.89

8.15 Autres patterns utiles

Usage Pattern Exemple valide
Numero de securite sociale FR ^[12]\d{2}(?:0[1-9]|1[0-2])\d{2}\d{3}\d{3}\d{2}$ 185037512300145
SIRET (14 chiffres) ^\d{14}$ 12345678901234
SIREN (9 chiffres) ^\d{9}$ 123456789
Plaque d'immatriculation FR (SIV) ^[A-Z]{2}-\d{3}-[A-Z]{2}$ AB-123-CD
UUID v4 ^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$ 550e8400-e29b-41d4-a716-446655440000
Couleur hexadecimale CSS ^#(?:[0-9A-Fa-f]{3}){1,2}$ #FF5733, #abc
Version semantique (SemVer) ^\d+\.\d+\.\d+(?:-[\w.]+)?(?:\+[\w.]+)?$ 2.1.0, 1.0.0-beta.1
Nom de variable (JS/PHP) ^[a-zA-Z_$][\w$]*$ maVariable, _count, $prix
Balise d'ouverture HTML <([a-z][\w-]*)(?:\s[^>]*)?\s*> <div class="test">
Hashtag (reseaux sociaux) #[a-zA-Z\u00C0-\u024F][\w\u00C0-\u024F]* #Regex, #DevWeb
Attention : Ces patterns sont des approximations pratiques. Par exemple, la validation d'email par regex ne peut pas couvrir 100% de la RFC 5322. Pour une validation rigoureuse, combinez la regex avec une verification cote serveur (envoi d'email de confirmation, resolution DNS du domaine, etc.).

9. Regex en JavaScript

En JavaScript, les regex sont des objets de premiere classe. On peut les creer avec la notation litterale /pattern/flags ou via le constructeur new RegExp().

9.1 Creer une regex

// Notation litterale (recommandee pour les patterns statiques)
const regex1 = /bonjour/gi;

// Constructeur RegExp (utile quand le pattern est dynamique)
const motRecherche = "bonjour";
const regex2 = new RegExp(motRecherche, "gi");

// Attention : avec le constructeur, il faut doubler les antislash
const regexChiffres = new RegExp("\\d+");  // equivalent de /\d+/

9.2 Methodes principales

Methode Description Retourne
regex.test(str) Teste si le pattern correspond true ou false
regex.exec(str) Execute la regex et retourne les details de la correspondance Array ou null
str.match(regex) Trouve les correspondances Array ou null
str.matchAll(regex) Iterateur sur toutes les correspondances (avec groupes) Iterator
str.replace(regex, remplacement) Remplace les correspondances Nouvelle chaine
str.replaceAll(regex, remplacement) Remplace toutes les correspondances (flag g requis) Nouvelle chaine
str.search(regex) Trouve l'index de la premiere correspondance Index (number) ou -1
str.split(regex) Decoupe la chaine selon le pattern Array de sous-chaines

9.3 Exemples pratiques

// ===== test() : validation rapide =====
const emailRegex = /^[\w.+-]+@[\w-]+\.[\w.]+$/;
emailRegex.test("user@example.com");    // true
emailRegex.test("invalide@");           // false

// Validation de mot de passe fort
const mdpRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[\W_]).{8,}$/;
mdpRegex.test("MonMdp2024!");           // true
mdpRegex.test("faible");               // false


// ===== match() : trouver des correspondances =====
const texte = "Appelez le 01 23 45 67 89 ou le 06 78 90 12 34";
const telRegex = /0[1-9](?:[\s.-]?\d{2}){4}/g;
texte.match(telRegex);
// Resultat : ["01 23 45 67 89", "06 78 90 12 34"]


// ===== matchAll() : correspondances avec groupes de capture =====
const html = '<a href="page1.html">Lien 1</a> et <a href="page2.html">Lien 2</a>';
const lienRegex = /href="([^"]+)">([^<]+)/g;
for (const match of html.matchAll(lienRegex)) {
    console.log(`URL: ${match[1]}, Texte: ${match[2]}`);
}
// URL: page1.html, Texte: Lien 1
// URL: page2.html, Texte: Lien 2


// ===== replace() : remplacement avec captures =====
// Reformater une date de JJ/MM/AAAA vers AAAA-MM-JJ
const date = "25/12/2024";
date.replace(/(\d{2})\/(\d{2})\/(\d{4})/, "$3-$2-$1");
// Resultat : "2024-12-25"

// Remplacer avec une fonction de callback
const prix = "Le produit coute 19.99 EUR et l'autre 5.50 EUR";
prix.replace(/(\d+\.\d{2})\s*EUR/g, (match, montant) => {
    return `${(parseFloat(montant) * 1.20).toFixed(2)} EUR TTC`;
});
// Resultat : "Le produit coute 23.99 EUR TTC et l'autre 6.60 EUR TTC"

// Nettoyer les espaces multiples
"  Hello    World  ".replace(/\s+/g, " ").trim();
// Resultat : "Hello World"


// ===== exec() : iteration detaillee =====
const codeRegex = /(?<code>\d{2})(?<ville>\d{3})/g;
const cp = "75001 13100 69003";
let result;
while ((result = codeRegex.exec(cp)) !== null) {
    console.log(`Dept: ${result.groups.code}, Ville: ${result.groups.ville}`);
}
// Dept: 75, Ville: 001
// Dept: 13, Ville: 100
// Dept: 69, Ville: 003


// ===== split() : decoupage avec regex =====
"pomme, banane; cerise  orange".split(/[,;\s]+/);
// Resultat : ["pomme", "banane", "cerise", "orange"]

"2024-01-15T14:30:00".split(/[-T:]/);
// Resultat : ["2024", "01", "15", "14", "30", "00"]


// ===== search() : trouver la position =====
"Bonjour le monde".search(/monde/);
// Resultat : 12 (position du debut de "monde")

"Pas de chiffre ici".search(/\d/);
// Resultat : -1 (pas trouve)
Astuce JavaScript : Attention avec exec() et le flag g : la regex garde un etat interne (lastIndex). Si vous reutilisez la meme regex, pensez a reinitialiser regex.lastIndex = 0 ou utilisez matchAll() qui est plus previsible.

10. Regex en PHP

PHP utilise les fonctions PCRE (Perl Compatible Regular Expressions) via les fonctions preg_*. Les patterns doivent etre entoures de delimiteurs (generalement /).

10.1 Fonctions principales

Fonction Description Retourne
preg_match($pattern, $subject, &$matches) Cherche la premiere correspondance 1 (trouve), 0 (pas trouve), false (erreur)
preg_match_all($pattern, $subject, &$matches) Cherche toutes les correspondances Nombre de correspondances ou false
preg_replace($pattern, $replacement, $subject) Remplace les correspondances Chaine modifiee ou null
preg_replace_callback($pattern, $callback, $subject) Remplace via une fonction de callback Chaine modifiee ou null
preg_split($pattern, $subject) Decoupe la chaine selon le pattern Array de sous-chaines ou false
preg_quote($str, $delimiter) Echappe les caracteres speciaux regex Chaine echappee
preg_grep($pattern, $array) Filtre un tableau selon le pattern Array des elements correspondants

10.2 Exemples pratiques

// ===== preg_match() : premiere correspondance =====

// Valider un email
$email = "user@example.com";
if (preg_match('/^[\w.+-]+@[\w-]+\.[\w.]+$/', $email)) {
    echo "Email valide";
}

// Extraire des groupes de capture
$date = "25/12/2024";
if (preg_match('/^(\d{2})\/(\d{2})\/(\d{4})$/', $date, $matches)) {
    echo "Jour: {$matches[1]}, Mois: {$matches[2]}, Annee: {$matches[3]}";
    // Jour: 25, Mois: 12, Annee: 2024
}

// Groupes nommes
$url = "https://www.example.com:8080/page";
$pattern = '/^(?P<protocole>https?):\/\/(?P<domaine>[\w.-]+)(?::(?P<port>\d+))?/';
if (preg_match($pattern, $url, $matches)) {
    echo "Protocole: {$matches['protocole']}";  // https
    echo "Domaine: {$matches['domaine']}";      // www.example.com
    echo "Port: {$matches['port']}";            // 8080
}


// ===== preg_match_all() : toutes les correspondances =====

// Trouver tous les numeros de telephone dans un texte
$texte = "Appelez le 01 23 45 67 89 ou le 06-78-90-12-34";
$nb = preg_match_all('/0[1-9](?:[\s.-]?\d{2}){4}/', $texte, $matches);
echo "$nb numeros trouves : " . implode(", ", $matches[0]);
// 2 numeros trouves : 01 23 45 67 89, 06-78-90-12-34

// Extraire tous les liens d'un document HTML
$html = '<a href="page1.html">Lien 1</a> <a href="page2.html">Lien 2</a>';
preg_match_all('/href="([^"]+)"/', $html, $matches);
// $matches[0] = ['href="page1.html"', 'href="page2.html"']
// $matches[1] = ['page1.html', 'page2.html']

// Extraire les paires cle=valeur
$config = "nom=Jean age=30 ville=Paris";
preg_match_all('/(\w+)=(\w+)/', $config, $matches, PREG_SET_ORDER);
foreach ($matches as $m) {
    echo "{$m[1]} => {$m[2]}\n";
}
// nom => Jean
// age => 30
// ville => Paris


// ===== preg_replace() : remplacement =====

// Reformater une date
$date = "25/12/2024";
$resultat = preg_replace('/(\d{2})\/(\d{2})\/(\d{4})/', '$3-$2-$1', $date);
// "2024-12-25"

// Nettoyer les espaces multiples
$texte = "  Trop    d'espaces    ici  ";
$propre = trim(preg_replace('/\s+/', ' ', $texte));
// "Trop d'espaces ici"

// Supprimer les balises HTML
$html = "<p>Texte <strong>en gras</strong></p>";
$texteBrut = preg_replace('/<[^>]+>/', '', $html);
// "Texte en gras"

// Remplacement avec tableau de patterns
$texte = "Lundi 01/01 et Mardi 02/01";
$resultat = preg_replace(
    ['/Lundi/', '/Mardi/', '/(\d{2})\/(\d{2})/'],
    ['Monday', 'Tuesday', '$2-$1'],
    $texte
);
// "Monday 01-01 et Tuesday 01-02"


// ===== preg_replace_callback() : remplacement dynamique =====

// Convertir des montants EUR -> USD (avec calcul)
$texte = "Prix : 100.00 EUR et 250.50 EUR";
$resultat = preg_replace_callback(
    '/(\d+\.\d{2})\s*EUR/',
    function ($matches) {
        $usd = round(floatval($matches[1]) * 1.10, 2);
        return "$usd USD";
    },
    $texte
);
// "Prix : 110.00 USD et 275.55 USD"

// Transformer le premier caractere de chaque mot en majuscule
$texte = "bonjour le monde";
$resultat = preg_replace_callback('/\b\w/', function ($m) {
    return strtoupper($m[0]);
}, $texte);
// "Bonjour Le Monde"


// ===== preg_split() : decoupage =====

// Decouper par plusieurs separateurs
$chaine = "pomme, banane; cerise  orange|kiwi";
$fruits = preg_split('/[,;\s|]+/', $chaine);
// ["pomme", "banane", "cerise", "orange", "kiwi"]

// Decouper un CSV avec guillemets
$ligne = '"Nom","Prenom","Age"';
$colonnes = preg_split('/","/', trim($ligne, '"'));
// ["Nom", "Prenom", "Age"]


// ===== preg_grep() : filtrer un tableau =====

$fichiers = ["index.php", "style.css", "app.js", "config.php", "logo.png"];

// Garder uniquement les fichiers PHP
$phpFiles = preg_grep('/\.php$/', $fichiers);
// ["index.php", "config.php"]

// Exclure les fichiers PHP (flag PREG_GREP_INVERT)
$autresFichiers = preg_grep('/\.php$/', $fichiers, PREG_GREP_INVERT);
// ["style.css", "app.js", "logo.png"]


// ===== preg_quote() : echapper pour insertion dans un pattern =====

$recherche = "prix (en $)";
$pattern = '/\b' . preg_quote($recherche, '/') . '\b/';
// Le pattern resultant echappe les ( ) et $ correctement
Astuce PHP : Utilisez toujours le flag u (Unicode/UTF-8) dans vos patterns si vous travaillez avec du texte francais ou multilingue : '/[\w]+/u'. Sans ce flag, les caracteres accentues ne seront pas reconnus par \w.

11. Regex en Bash (grep, sed, awk)

En ligne de commande Linux, les outils grep, sed et awk utilisent des expressions regulieres pour rechercher, filtrer et transformer du texte. Il existe deux types de regex : BRE (Basic) et ERE (Extended).

11.1 BRE vs ERE

Caractere BRE (Basic) ERE (Extended) Commande
+ \+ + BRE = grep, ERE = grep -E / egrep
? \? ? BRE = sed, ERE = sed -E
{n,m} \{n,m\} {n,m} ERE = awk (utilise ERE par defaut)
(...) \(...\) (...) PCRE = grep -P (si disponible)
| \| |

11.2 grep - Recherche dans les fichiers

# Recherche basique (BRE)
grep "motif" fichier.txt

# Recherche avec regex etendue (ERE) - recommande
grep -E "motif" fichier.txt

# Recherche avec PCRE (Perl Compatible) - le plus puissant
grep -P "motif" fichier.txt

# Options utiles
grep -i "motif" fichier.txt          # Insensible a la casse
grep -n "motif" fichier.txt          # Afficher les numeros de ligne
grep -c "motif" fichier.txt          # Compter les correspondances
grep -l "motif" *.txt                # Lister les fichiers correspondants
grep -r "motif" /chemin/dossier/     # Recherche recursive
grep -v "motif" fichier.txt          # Inverser (lignes ne correspondant PAS)
grep -w "mot" fichier.txt            # Mot entier uniquement
grep -o "motif" fichier.txt          # Afficher uniquement la partie correspondante
grep -A 3 "motif" fichier.txt        # 3 lignes apres chaque correspondance
grep -B 2 "motif" fichier.txt        # 2 lignes avant chaque correspondance
grep -C 2 "motif" fichier.txt        # 2 lignes avant ET apres

# Exemples concrets
# Trouver les lignes contenant une adresse IP
grep -E "\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b" access.log

# Trouver les erreurs 404 et 500 dans les logs Apache
grep -E "\" (404|500) " /var/log/apache2/access.log

# Lister les fichiers PHP contenant "password" (recursive)
grep -rl "password" /var/www/ --include="*.php"

# Trouver les TODO/FIXME dans le code
grep -rn -E "(TODO|FIXME|HACK|XXX)" /var/www/projet/ --include="*.{php,js}"

# Compter les lignes vides dans un fichier
grep -c "^$" fichier.txt

# Afficher les lignes commencant par un commentaire (#)
grep -E "^\s*#" config.conf

# Trouver les adresses email dans un fichier
grep -oE "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}" fichier.txt

11.3 sed - Recherche et remplacement

# Syntaxe de base : sed 's/recherche/remplacement/flags' fichier
# Flag g = global (toutes les occurrences), sans g = premiere seulement

# Remplacement simple
sed 's/ancien/nouveau/g' fichier.txt

# Avec regex etendue (recommande)
sed -E 's/motif/remplacement/g' fichier.txt

# Modifier le fichier en place (attention, pas de retour arriere !)
sed -i 's/ancien/nouveau/g' fichier.txt

# Modifier en place avec backup
sed -i.bak 's/ancien/nouveau/g' fichier.txt

# Exemples concrets

# Reformater des dates JJ/MM/AAAA en AAAA-MM-JJ
sed -E 's/([0-9]{2})\/([0-9]{2})\/([0-9]{4})/\3-\2-\1/g' dates.txt

# Supprimer les balises HTML
sed -E 's/<[^>]+>//g' page.html

# Supprimer les lignes vides
sed '/^$/d' fichier.txt

# Supprimer les espaces en fin de ligne (trailing whitespace)
sed -E 's/\s+$//' fichier.txt

# Supprimer les commentaires (#) d'un fichier de configuration
sed -E '/^\s*#/d' config.conf

# Ajouter un prefixe a chaque ligne
sed 's/^/PREFIX: /' fichier.txt

# Remplacer uniquement sur les lignes contenant un motif
sed '/ERROR/s/warning/CRITICAL/g' log.txt

# Supprimer les lignes 5 a 10
sed '5,10d' fichier.txt

# Extraire entre deux patterns (inclusif)
sed -n '/DEBUT/,/FIN/p' fichier.txt

# Inserer une ligne apres un motif
sed '/pattern/a\Nouvelle ligne inseree' fichier.txt

# Remplacer uniquement la 3eme occurrence par ligne
sed 's/motif/remplacement/3' fichier.txt

# Changement de delimiteur (utile avec des chemins)
sed 's|/var/www/ancien|/var/www/nouveau|g' config.conf

11.4 awk - Traitement de texte avance

# Syntaxe : awk '/pattern/ {action}' fichier

# Afficher les lignes correspondant a un motif
awk '/ERROR/' log.txt

# Afficher une colonne specifique (espace comme separateur par defaut)
awk '{print $1}' fichier.txt                # 1ere colonne
awk '{print $NF}' fichier.txt               # Derniere colonne

# Separateur personnalise (CSV, etc.)
awk -F',' '{print $2}' fichier.csv          # 2eme colonne d'un CSV
awk -F':' '{print $1, $3}' /etc/passwd      # Login et UID

# Exemples avec regex

# Lignes ou le 3eme champ correspond a un motif
awk '$3 ~ /^[0-9]+$/ {print $0}' fichier.txt

# Lignes ou le 1er champ NE correspond PAS
awk '$1 !~ /^#/' config.conf

# Extraire les adresses IP uniques d'un log Apache
awk '{print $1}' access.log | sort -u

# Compter les occurrences de chaque code HTTP
awk '{print $9}' access.log | sort | uniq -c | sort -rn

# Calculer la somme d'une colonne pour les lignes correspondantes
awk -F',' '/vente/ {somme += $3} END {print "Total:", somme}' rapport.csv

# Afficher les lignes entre deux motifs
awk '/DEBUT/,/FIN/' fichier.txt

# Formater la sortie
awk -F':' '{printf "%-20s UID: %s\n", $1, $3}' /etc/passwd

# Remplacer un champ selon une condition
awk -F',' 'BEGIN{OFS=","} $3 > 100 {$3 = "ELEVE"} {print}' donnees.csv

11.5 Combinaisons utiles

# Trouver et remplacer recursivement dans tous les fichiers PHP
find /var/www -name "*.php" -exec sed -i 's/ancien/nouveau/g' {} +

# Extraire les erreurs uniques d'un log
grep -oE "Error: .*$" application.log | sort -u

# Compter les occurrences d'un motif par fichier
grep -rc "TODO" /var/www/projet/ --include="*.php" | grep -v ":0$"

# Extraire les URL d'un fichier HTML
grep -oE 'https?://[^"'"'"'> ]+' page.html | sort -u

# Surveiller un log en temps reel avec filtrage
tail -f /var/log/syslog | grep --line-buffered -E "(error|warning|critical)"

# Renommer en masse des fichiers (avec rename)
# Remplacer les espaces par des underscores
rename 's/ /_/g' *.txt

# Trouver les fichiers modifies contenant un pattern
find . -name "*.php" -newer reference.txt -exec grep -l "pattern" {} +
Astuce Bash : Privilegiez grep -E (ERE) ou grep -P (PCRE) plutot que le grep de base (BRE). La syntaxe ERE est plus proche de ce qu'on utilise en JavaScript/PHP, et PCRE offre les fonctionnalites les plus avancees (lookahead, lookbehind, \d, \w, etc.).

12. Erreurs courantes et performance

12.1 Erreurs frequentes

Erreur Probleme Solution
Oublier d'echapper le point 192.168.1.1 correspond aussi a 192x168y1z1 Utiliser 192\.168\.1\.1
Quantificateur gourmand par defaut <.*> capture tout de la premiere < a la derniere > Utiliser <.*?> (lazy) ou <[^>]+>
Ne pas ancrer le pattern \d{5} matche "123456" (prend les 5 premiers) Utiliser ^\d{5}$ pour une correspondance exacte
Confondre [ ] et ( ) [abc] = un caractere parmi a,b,c ; (abc) = la sequence "abc" Utiliser [] pour les classes, () pour les groupes
Oublier le flag g Seule la premiere correspondance est trouvee/remplacee Ajouter le flag g pour traiter toutes les occurrences
Le tiret mal place dans [] [a-z-0] peut etre mal interprete Mettre le tiret en debut ou fin : [-a-z0] ou [a-z0-]
Doubler les \ en string "\d+" ne fonctionne pas en JS (constructeur) ou PHP Utiliser "\\d+" dans les strings, ou /\d+/ en litteral
Utiliser regex pour du HTML complexe Les regex ne gerent pas les structures imbriquees Utiliser un parseur DOM (DOMDocument en PHP, DOMParser en JS)

12.2 Backtracking (retour en arriere)

Le backtracking est le mecanisme par lequel le moteur regex revient en arriere pour essayer d'autres chemins lorsqu'une tentative de correspondance echoue. C'est normal, mais un exces de backtracking peut rendre une regex extremement lente.

# Comment fonctionne le backtracking ?
# Regex : /a.*b/ sur le texte "a]]]]]]]]]b"
#
# 1. "a" correspond au premier "a"
# 2. ".*" est gourmand : il consomme TOUT le reste "]]]]]]]]b"
# 3. Le moteur essaie de faire correspondre "b" : il n'y a plus rien -> echec
# 4. Le moteur recule d'un caractere (backtrack) : ".*" = "]]]]]]]]"
# 5. Il essaie "b" sur "b" : correspondance trouvee !
#
# Ici le backtracking est minime (1 retour). Mais avec certains patterns...

12.3 Catastrophic Backtracking

Certaines combinaisons de patterns et de textes provoquent un backtracking exponentiel, rendant la regex pratiquement infinie. C'est ce qu'on appelle le catastrophic backtracking (ou ReDoS - Regular Expression Denial of Service).

# DANGER : patterns a eviter (catastrophic backtracking)

# Pattern 1 : quantificateurs imbriques
(a+)+b
# Sur le texte "aaaaaaaaaaaaaaaaaac" (pas de b a la fin)
# Le moteur essaie TOUTES les manieres de repartir les "a" entre les groupes
# Temps exponentiel : 2^n combinaisons !

# Pattern 2 : alternance avec chevauchement
(a|aa)+b
# Meme probleme : multiples facons de decomposer "aaaa..."

# Pattern 3 : repetitions chevauchantes
(\w+\s*)*$
# Sur "mot1 mot2 mot3 mot4 mot5 !" (finit par un caractere non-\w)
# Backtracking exponentiel

# Pattern 4 : nested quantifiers sur classe large
(.*a){10}
# Sur un texte sans assez de "a" : explosion combinatoire

12.4 Bonnes pratiques de performance

Pratique Mauvais Bon Pourquoi
Eviter les quantificateurs imbriques (a+)+ a+ Supprime le backtracking exponentiel
Utiliser des classes negees <.*?> <[^>]+> Evite le backtracking du lazy quantifier
Etre specifique .+@.+\..+ [\w.+-]+@[\w-]+\.\w+ Reduit les correspondances inutiles
Ancrer les patterns \d{5} ^\d{5}$ Empeche les tentatives a chaque position
Groupes non-capturants (abc|def)+ (?:abc|def)+ Evite le cout de sauvegarde des captures
Quantificateurs possessifs \w+\d \w++\d (PCRE) Pas de backtracking (le moteur ne recule jamais)
Atomic groups (?>abc|ab)c (?>abc|ab)c (PCRE) Empeche le backtracking dans le groupe

12.5 Tester la performance

// JavaScript : mesurer le temps d'execution
const debut = performance.now();
const regex = /votre_pattern/g;
const resultat = texte.match(regex);
const duree = performance.now() - debut;
console.log(`Temps: ${duree.toFixed(2)} ms, Resultats: ${resultat?.length ?? 0}`);

// PHP : mesurer le temps d'execution
$debut = microtime(true);
preg_match_all('/votre_pattern/', $texte, $matches);
$duree = (microtime(true) - $debut) * 1000;
echo "Temps: " . number_format($duree, 2) . " ms, Resultats: " . count($matches[0]);

// PHP : limiter le backtracking (php.ini ou ini_set)
ini_set('pcre.backtrack_limit', 1000000);  // defaut
ini_set('pcre.recursion_limit', 100000);   // defaut

// Bash : mesurer avec time
time grep -cP 'pattern' gros_fichier.log
Attention securite (ReDoS) : Si votre application accepte des regex de la part des utilisateurs (champs de recherche avances, filtres personnalises), vous etes vulnerable aux attaques ReDoS (Regular Expression Denial of Service). Un utilisateur malveillant peut soumettre un pattern concu pour provoquer un catastrophic backtracking et bloquer votre serveur. Contremesures :
  • Ne jamais executer directement une regex fournie par l'utilisateur
  • Limiter la longueur du pattern et du texte a analyser
  • Utiliser un timeout (pcre.backtrack_limit en PHP)
  • Valider le pattern avec un analyseur statique avant execution
  • Envisager des alternatives (recherche par sous-chaines, index full-text)
Astuce finale : Les expressions regulieres sont un outil extremement puissant mais elles ne sont pas la solution a tout. Pour parser du HTML complexe, du XML, du JSON ou du CSV, utilisez des parseurs dedies. Reservez les regex pour la validation de formats simples, la recherche de motifs dans du texte brut et les transformations rapides. Comme le dit la citation celebre : "Certaines personnes, confrontees a un probleme, se disent : 'Je vais utiliser une regex.' Desormais, elles ont deux problemes." - Jamie Zawinski.