16 - Quand ne PAS utiliser les regex
Ce que tu vas apprendre
- Les cas ou une regex est la mauvaise réponse
- Les API natives de JavaScript qui font mieux le travail
- Pourquoi la lisibilité compte plus que la puissance
- Quand passer a un vrai parser (PEG, ANTLR)
Prerequisites
- 15 - Parsing du monde réel
- Avoir souffert au moins une fois en debuggant une regex trop complexe
Quand tu maitrises les regex, tu commences a les voir partout. Chaque problème de texte devient un clou, et ta regex est le marteau. J'ai vecu cette phase. J'ecrivais des regex pour tout : valider des emails, parser du JSON, extraire des donnees d'URL. Et a chaque fois, le code etait fragile, illisible, et cassait sur des cas limites que je n'avais pas prevus.
Voici les situations ou tu devrais poser ta regex et prendre un autre outil.
JSON : utilise JSON.parse
J'ai vu des gens écrire des regex pour extraire une valeur d'un JSON. Vraiment.
javascript// Non. Juste... non.
const json = '{"name": "Nicolas", "age": 30}';
const name = json.match(/"name":\s*"([^"]+)"/)[1];
// Oui.
const data = JSON.parse(json);
const name = data.name;
Pourquoi la regex echoue :
- Les chaînes JSON peuvent contenir des guillemets echappes (
\") - Les valeurs peuvent etre des nombres, des booleens, des tableaux, des objets imbriques
- L'espacement est variable
- Les clés peuvent etre dans n'importe quel ordre
JSON.parse gere tout ca en une ligne. Et si le JSON est invalide, il leve une exception propre au lieu de retourner null silencieusement.
URLs : utilise l'API URL
javascript// Fragile et incomplet
const url = "https://example.com:8080/path?key=value&foo=bar#section";
const match = url.match(/^(https?):\/\/([^:\/]+)(?::(\d+))?(\/[^?#]*)?(?:\?([^#]*))?(?:#(.*))?$/);
// Bonne chance pour te souvenir de quel groupe est quoi
// Robuste et lisible
const parsed = new URL(url);
console.log(parsed.protocol); // "https:"
console.log(parsed.hostname); // "example.com"
console.log(parsed.port); // "8080"
console.log(parsed.pathname); // "/path"
console.log(parsed.searchParams.get("key")); // "value"
console.log(parsed.hash); // "#section"
L'API URL gere l'encodage percent, les URLs internationalisees, les cas limites du standard RFC 3986... Ta regex ne le fait pas. Et URLSearchParams te donne un acces propre aux paramètres de query string.
Le seul cas ou une regex sur une URL se justifie : quand tu cherches un pattern dans un lot d'URLs (par exemple, trouver toutes les URLs contenant /api/v[0-9]+/ dans des logs). La, c'est du pattern matching, pas du parsing.
HTML : utilise DOMParser
On en a parle dans l'article précédent, mais ca merite d'etre répété parce que c'est la tentation la plus courante.
javascript// Ceci va casser. La question est quand, pas si.
const html = '<div class="user" data-id="42">Nicolas</div>';
const content = html.match(/<div[^>]*>(.*?)<\/div>/)[1];
// Correct
const parser = new DOMParser();
const doc = parser.parseFromString(html, "text/html");
const content = doc.querySelector(".user").textContent;
Le HTML est un langage avec des regles d'imbrication, des entités, des commentaires, du CDATA, des attributs sans guillemets, des balises auto-fermantes... Les regex operent sur du texte plat. La mismatch est fondamentale.
Cote serveur (Node.js), utilise cheerio ou linkedom. Ils parsent le HTML correctement et t'offrent une API jQuery-like.
Validation d'email : utilise une librairie
La regex "complète" pour valider une adresse email selon la RFC 5322 fait plus de 6000 caractères. Personne ne veut maintenir ca.
javascript// La regex "simple" qui laisse passer des emails invalides
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
// La regex "complete" qui... non, je ne vais pas la coller ici
// Avec Zod : propre, maintenable, et correctement teste
import { z } from "zod";
const emailSchema = z.string().email();
emailSchema.parse("nicolas@example.com"); // OK
emailSchema.parse("pas-un-email"); // ZodError
Zod, Yup, Valibot... ces librairies de validation sont testees par des milliers de développeurs. Leur regex interne est auditee et mise à jour. Ta regex artisanale ne l'est pas.
Et en réalité, la meilleure validation d'email c'est d'envoyer un email de confirmation. Aucune regex ne peut te dire si nicolas@example.com est une adresse qui existe.
Opérations simples sur les chaînes : utilise les méthodes natives
Celui-la me fait mal parce que je l'ai fait trop souvent. Utiliser une regex quand une méthode de String suffit.
javascriptconst filename = "photo-vacances.jpg";
// Excessif
if (/\.jpg$/.test(filename)) { /* ... */ }
if (/^photo/.test(filename)) { /* ... */ }
if (/vacances/.test(filename)) { /* ... */ }
// Direct
if (filename.endsWith(".jpg")) { /* ... */ }
if (filename.startsWith("photo")) { /* ... */ }
if (filename.includes("vacances")) { /* ... */ }
javascriptconst csv = "pomme,poire,cerise";
// Excessif
const fruits = csv.split(/,/);
// Direct (pas besoin de regex pour un separateur fixe)
const fruits = csv.split(",");
javascriptconst text = " du texte avec des espaces ";
// Excessif
const trimmed = text.replace(/^\s+|\s+$/g, "");
// Direct
const trimmed = text.trim();
La regex compile un automate a chaque exécution (sauf si tu la mets dans une constante). Les méthodes natives sont optimisees en C++ dans le moteur. Sur des milliers d'appels, la différence est mesurable.
La lisibilité avant la puissance
Voici une regex que j'ai trouvee dans un projet en production :
javascriptconst dateRegex = /^(?:(?:31(\/|-|\.)(?:0?[13578]|1[02]))\1|(?:(?:29|30)(\/|-|\.)(?:0?[13-9]|1[0-2])\2))(?:(?:1[6-9]|[2-9]\d)?\d{2})$|^(?:29(\/|-|\.)0?2\3(?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:0?[1-9]|1\d|2[0-8])(\/|-|\.)(?:(?:0?[1-9])|(?:1[0-2]))\4(?:(?:1[6-9]|[2-9]\d)?\d{2})$/;
Elle valide des dates en tenant compte des annees bissextiles. C'est techniquement impressionnant. C'est aussi complètement inmaintenable. Personne dans l'équipe ne pouvait la modifier avec confiance.
L'alternative :
javascriptfunction isValidDate(dateStr) {
const parsed = new Date(dateStr);
return !isNaN(parsed.getTime());
}
// Ou avec une librairie comme date-fns / Temporal API
La regle que j'applique : si une regex dépassé une ligne, je me demande s'il existe une alternative plus lisible. Souvent, la réponse est oui.
Quand passer a un vrai parser
Les regex sont puissantes pour le pattern matching sur du texte plat. Mais elles ne gerent pas :
- Les structures imbriquees : HTML, XML, JSON, code source
- Les grammaires contextuelles : Markdown (ou un
*peut etre italique, liste, ou litteral selon le contexte) - Les langages de programmation : meme un simple tokenizer de calculatrice dépassé ce que les regex font confortablement
Pour ces cas, il existe des outils dédiés :
| Besoin | Outil |
|---|---|
| Grammaire simple (DSL, config) | PEG.js / Peggy |
| Grammaire complexe (langage) | ANTLR, Tree-sitter |
| Markdown | marked, remark |
| HTML | DOMParser, cheerio |
| CSS selectors | PostCSS |
| JSON | JSON.parse, jq |
| YAML | js-yaml |
| TOML | @iarna/toml |
Un parser PEG est souvent plus simple qu'on ne le croit. Si tu te retrouves a écrire une regex de plus de 200 caractères, c'est le signe qu'un parser serait plus adapte. Un article sur les parsers combinators est disponible sur paltemps.fr.
L'arbre de décision
Avant d'écrire une regex, pose-toi ces questions :
- Est-ce une recherche de pattern dans du texte ? Oui -> regex probablement OK
- Est-ce du parsing d'un format connu (JSON, URL, HTML) ? Oui -> utilise l'API dédiée
- Est-ce une opération simple (contient, commence par, finit par) ? Oui -> méthode String native
- Est-ce de la validation (email, date, numero de tel) ? Oui -> librairie de validation
- La structure est-elle imbriquee ou recursive ? Oui -> vrai parser
- La regex dépassé-t-elle une ligne ? Oui -> questionne-toi serieusement
Résumé
- JSON :
JSON.parse, jamais de regex - URLs :
new URL()etURLSearchParams - HTML :
DOMParser(navigateur) oucheerio(serveur) - Emails : Zod
.email()ou une librairie de validation - Opérations simples :
.includes(),.startsWith(),.endsWith(),.split() - Dates complexes : API Date ou librairie dédiée
- Structures imbriquees : PEG, ANTLR, ou un parser spécifique au format
- La lisibilité et la maintenabilité passent avant l'elegance technique
Article précédent : 15 - Parsing du monde réel Article suivant : 17 - Glossaire