Guides

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.

Logo de Regex Hunter

· 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 tiers regex ajoute 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 avec perl = TRUE.
  • RE2 : la bibliothèque de Google. Le paquet regexp de Go suit sa syntaxe et sa garantie de vitesse, tout comme REGEXMATCH de Google Sheets et REGEXP_CONTAINS de 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
  1. La documentation de Java demande une longueur maximale bornée, mais Java 17 a aussi accepté (?<=a+) dans notre test. Ne comptez pas dessus.
  2. Par défaut, \d dans PCRE2 est ASCII. Le marqueur /u de PHP active le mode UCP, d'où la correspondance de \d avec ٣.
  3. 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.
  4. 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 :

Correspondances4/4 comme prévu
/\$\s*(\d+)/

Doit correspondre2/2

  • Total: $40
  • Total: $ 40

Ne doit pas2/2

  • Total: 40
  • Total: USD 40
Essayez-le dans le bac à sable

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 marqueur m quand vous parlez de lignes, ou \A…\z cô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.