Moteurs regex comparés : JavaScript, Python, Java, PCRE et RE2
Quelles fonctionnalités regex marchent dans quel moteur, testées côte à côte : lookbehind, groupes nommés, Unicode, groupes atomiques, récursion, comportement de $ avant un saut de ligne, et quels moteurs peuvent bloquer sur un mauvais motif.

· 7 min de lecture
/\$\s*(\d+)/
à attraper
- $40
- $ 40
- $5
à épargner
- 40
- USD 40
- $x
JavaScript, Python, Java et PCRE sont tous des moteurs regex à backtracking avec presque la même syntaxe de base, donc la plupart des motifs courants fonctionnent dans les quatre. Ils diffèrent sur les détails qui cassent le code quand vous déplacez un motif : la quantité de lookbehind autorisée, l'écriture des groupes nommés, si \d reconnaît les chiffres d'autres écritures, et ce que fait $ avant un saut de ligne final. RE2 (utilisé par Go, Google Sheets et BigQuery) fait figure d'exception : il renonce aux références arrière et aux lookarounds en échange de la garantie que la recherche ne prend jamais plus qu'un temps linéaire.
Chaque ligne ci-dessous a été testée le 4 novembre 2026, pas recopiée d'une documentation : Node 22.23 pour JavaScript, Python 3.12.6 (re), Java 17.0.20 (java.util.regex), PCRE2 10.44 via PHP 8.5, et RE2 via le paquet google-re2 1.1 de Google. Les versions plus récentes peuvent en prendre en charge davantage.
01Où vous rencontrerez chaque moteur
- JavaScript : tous les navigateurs, Node, Deno et TypeScript. C'est aussi le moteur derrière les plateaux de ce site.
- Python : le module intégré
re. Le module tiersregexajoute une bonne partie de ce qui manque àre. - Java :
java.util.regex, qu'utilisent Kotlin et Scala sur la JVM. - PCRE2 : les fonctions
preg_de PHP,grep -P, nginx, et R avecperl = TRUE. - RE2 : la bibliothèque de Google. Le paquet
regexpde Go suit sa syntaxe et sa garantie de vitesse, tout commeREGEXMATCHde Google Sheets etREGEXP_CONTAINSde BigQuery.
02Le tableau des fonctionnalités
| JavaScript | Python re |
Java | PCRE2 | RE2 | |
|---|---|---|---|---|---|
Lookahead (?=…) |
Oui | Oui | Oui | Oui | Non |
Lookbehind (?<=…) |
Oui, toute longueur | Largeur fixe uniquement | Oui, longueur bornée¹ | Oui, longueur bornée | Non |
Références arrière \1 |
Oui | Oui | Oui | Oui | Non |
| Groupe nommé | (?<n>…) |
(?P<n>…) |
(?<n>…) |
Les deux | Les deux |
| Référence arrière nommée | \k<n> |
(?P=n) |
\k<n> |
Les deux | Non |
Groupe atomique (?>…) |
Non | Oui (3.11+) | Oui | Oui | Non |
Possessif a++ |
Non | Oui (3.11+) | Oui | Oui | Non |
Propriété Unicode \p{L} |
Oui, avec le marqueur u |
Non | Oui | Oui | Oui |
| Écriture, ex. grec | \p{Script=Greek} |
Non | \p{IsGreek} |
\p{Greek} |
\p{Greek} |
\d reconnaît ٣ (3 en chiffres arabes orientaux) |
Non | Oui | Non | Seulement en mode UCP² | Non |
Récursion (?R) |
Non | Non | Non | Oui | Non |
Conditionnel (?(1)…|…) |
Non | Oui | Non | Oui | Non |
Marqueurs en ligne (?i) |
Non³ | Oui | Oui | Oui | Oui |
^abc$ reconnaît "abc\n" |
Non | Oui | Oui | Oui | Non |
Fin du texte \z |
Non | Non, c'est \Z |
Oui | Oui | Oui |
| Peut bloquer sur un mauvais motif | Oui | Oui | Oui | S'arrête à une limite⁴ | Non |
- La documentation de Java demande une longueur maximale bornée, mais Java 17 a aussi accepté
(?<=a+)dans notre test. Ne comptez pas dessus. - Par défaut,
\ddans PCRE2 est ASCII. Le marqueur/ude PHP active le mode UCP, d'où la correspondance de\davec٣. - Node 22 rejette à la fois
(?i)et la forme délimitée(?i:…). La forme délimitée est apparue dans ES2025 et ne fonctionne que dans les environnements d'exécution récents. - Voir le test de vitesse ci-dessous : PHP a renvoyé une erreur au lieu d'une réponse.
03Les différences qui cassent les motifs déplacés
$ et un saut de ligne final
^abc$ reconnaît "abc\n" en Python, Java et PCRE, car leur $ correspond aussi juste avant un saut de ligne final. En JavaScript et RE2, non. Une ligne lue dans un fichier avec son saut de ligne passe la validation dans un langage et échoue dans un autre. Pour dire « la toute fin », utilisez \z en Java, PCRE et RE2, et \Z en Python (où \Z est la fin absolue). JavaScript n'a ni l'un ni l'autre : sans le marqueur m, son $ signifie déjà la toute fin.
Lookbehind
JavaScript autorise tout lookbehind, y compris de longueur variable comme (?<=\$\s*)\d+. Le re de Python n'autorise qu'une largeur fixe, PCRE2 une longueur bornée et RE2 aucun. La solution portable consiste à reconnaître le préfixe et à capturer plutôt ce que vous voulez :
/\$\s*(\d+)/Doit correspondre2/2
- Total: $40
- Total: $ 40
Ne doit pas2/2
- Total: 40
- Total: USD 40
Le groupe 1 contient le nombre dans tous les moteurs, RE2 compris.
Groupes nommés
(?<year>\d{4}) fonctionne en JavaScript, Java, PCRE2 et RE2, mais le re de Python 3.12 le rejette et exige (?P<year>\d{4}). Les références arrière à un nom diffèrent aussi : \k<year> en JavaScript, Java et PCRE, (?P=year) en Python. Regex en JavaScript et en Python donne la liste complète pour ces deux-là.
\d, \w et Unicode
En Python 3, \d et \w reconnaissent par défaut les chiffres et les lettres de toutes les écritures, donc \d accepte ٣. En JavaScript, Java et RE2, ils se limitent à l'ASCII. Pour un champ de formulaire qui doit être 0-9, écrivez [0-9] et le motif signifie la même chose partout (en Python, vous pouvez aussi passer re.ASCII).
Pour les lettres de n'importe quelle langue, \p{L} fonctionne en JavaScript (avec le marqueur u), Java, PCRE2 et RE2, mais pas dans le re de Python.
Groupes atomiques et quantificateurs possessifs
(?>a+) et a++ prennent autant qu'ils peuvent et ne rendent jamais rien, ce qui est un moyen d'arrêter un backtracking incontrôlé. Java et PCRE les ont depuis des années, et Python les a ajoutés en 3.11. JavaScript et RE2 ne les ont pas ; en JavaScript, un lookahead avec une référence arrière, (?=(a+))\1, fait le même travail.
04Vitesse : quels moteurs peuvent bloquer
Le mauvais motif classique est (a+)+$ face à une longue suite de la lettre a suivie de !. Un moteur à backtracking essaie toutes les façons de répartir la suite entre le + intérieur et le + extérieur avant d'abandonner. Voici ce qu'a fait chaque moteur avec 24 lettres et un ! :
| Moteur | Résultat |
|---|---|
| JavaScript (Node 22) | 11,2 secondes |
| Python 3.12 | 1,8 seconde |
| Java 17 | Moins de 1 ms |
| PCRE2 (PHP) | A abandonné au bout de 3 ms avec « Backtrack limit exhausted » |
| RE2 | Moins de 1 ms, même avec 100 000 lettres |
Deux points ressortent. Java 17 optimise cette forme, mais reste un moteur à backtracking : ajoutez une référence arrière, comme dans ^(a+)+\1$, et son temps est passé de 9 ms à 45 ms puis à 590 ms quand l'entrée est passée de 16 à 20 puis à 24 lettres. PHP ne se bloque pas, mais preg_match renvoie false, et un code qui vérifie seulement si la correspondance est vraie l'interprète comme « aucune correspondance » sans remarquer l'erreur.
Seul RE2 garantit un temps linéaire pour tous les motifs, c'est pourquoi c'est le choix sûr pour les motifs saisis par les utilisateurs. Le backtracking catastrophique explique comment repérer et corriger ces motifs dans n'importe quel moteur.
05Écrire un motif qui fonctionne partout
Si un motif doit tourner dans plusieurs moteurs, par exemple dans le navigateur et sur le serveur, ce sous-ensemble se comporte de la même façon dans les cinq :
- Le texte littéral, les classes comme
[a-z0-9_],., et les quantificateurs* + ? {n,m}avec leurs versions paresseuses. - Les ancres
^et$avec le marqueurmquand vous parlez de lignes, ou\A…\zcôté serveur quand vous parlez de tout le texte (et ne donnez jamais un saut de ligne final à un$JavaScript). - Les groupes
(…)et(?:…), et l'alternance|. [0-9]plutôt que\d, si les chiffres d'autres écritures doivent être rejetés.- Ni lookarounds ni références arrière si RE2 peut l'exécuter ; capturez plutôt la partie voulue.
Testez ensuite le motif dans chaque moteur où il tournera. Le Bac à sable utilise le moteur de JavaScript, comme cette page.
06S'entraîner
Les packs d'entraînement et la chasse du jour utilisent le moteur de JavaScript, donc lookbehind et groupes nommés y sont permis. Le Guide des regex couvre chaque fonctionnalité avec des exemples interactifs.