DanLevy.net

Quiz : Maîtrise des expressions régulières

Dominez les expressions régulières sauvages.

Prêt à vous battre avec des expressions régulières ? 🤼‍♂️

Testez vos connaissances en RegEx avec des questions portant sur les motifs de base, les quantificateurs, les groupes et ces assertions look‑around compliquées. Des correspondances de chaînes simples à la validation de motifs complexes – pouvez‑vous identifier la bonne expression régulière ?

Qu’est-ce qui correspond ?

'cat CAT Cat'.match(/cat/g)

Ce modèle utilise g, mais pas i :

  • g trouve toutes les correspondances
  • Sans i, la recherche est sensible à la casse

Sans le drapeau i, seule la chaîne en minuscules “cat” correspond.

C’est particulièrement utile lorsqu’on traite des entrées utilisateur ou du HTML où la casse peut varier.

En savoir plus sur les drapeaux RegExp

Que renverra ce code ?

const words = ['cat', 'hat', 'what', 'bat'];
words.filter(word => word.match(/^[ch]at/))

Le motif /^[ch]at/ correspond aux chaînes qui :

  • Commencent (^) par ‘c’ ou ‘h’ (c’est ce que signifie [ch] – une classe de caractères qui correspond à un seul caractère)
  • Suivies littéralement de ‘at’

Ainsi, seules “cat” et “hat” correspondent à ce motif. La méthode filter() ne conserve que les éléments correspondants.

En savoir plus sur les classes de caractères sur MDN

Que cela va-t-il correspondre ?

'<div>Hello</div><div>World</div>'.match(/<div>.*?<\/div>/g)

Le motif /<div>.*?<\/div>/g utilise une correspondance non‑gourmande avec *?, ce qui signifie :

  • Correspondre à <div>
  • Correspondre à n’importe quel caractère (.*) mais le moins possible (?)
  • Jusqu’à trouver </div>
  • Le drapeau g fait qu’il trouve toutes les occurrences

Sans le ?, le .* gourmand correspondrait à tout, du premier <div> au dernier </div>, produisant une seule grande correspondance. Avec le ?, il correspond à chaque paire séparément.

En savoir plus sur la correspondance gourmande vs paresseuse

Que renverra-t-il ?

'hello\nworld'.match(/\w+/g)

Le motif \w+ correspond à un ou plusieurs caractères alphanumériques. Même s’il y a un saut de ligne dans la chaîne, \w correspond à :

  • Lettres (a‑z, A‑Z)
  • Chiffres (0‑9)
  • Souligné (_)

Ainsi, le saut de ligne agit comme une frontière de mot, et nous obtenons deux correspondances. Si nous avions utilisé .*, il ne correspondrait pas au saut de ligne par défaut (il faudrait le drapeau s pour cela).

En savoir plus sur les métacaractères

Que va-t-il correspondre ?

'$100 and €50'.match(/\d+(?=[\$€])/g)

Ce motif ne correspondra à rien parce que le look‑ahead est inversé ! Si vous voulez des chiffres précédés de $ ou , utilisez un look‑behind : /(?<=[\$€])\d+/g.

Les look‑aheads vérifient ce qui vient après la position courante. Le motif tel qu’il est écrit recherche :

  • Un ou plusieurs chiffres (\d+)
  • Suivis de ((?=…)) soit $ soit € ([\$€])

Comme il n’y a aucun nombre suivi d’un symbole monétaire (ils sont précédés), aucune correspondance n’est trouvée.

En savoir plus sur les assertions look‑ahead

Qu’est-ce qui correspondra ?

'cat cats category'.match(/\bcat\b/g)

La \b représente une bordure de mot, qui correspond à :

  • Entre un caractère de mot et un caractère non‑mot
  • Au début ou à la fin de la chaîne s’il y a un caractère de mot

Ainsi /\bcat\b/ ne correspond à “cat” que lorsqu’il forme un mot complet, pas lorsqu’il fait partie d’un autre mot.

  • ✅ “cat” (entouré d’espaces)
  • ❌ “cats” (pas de bordure après “cat”)
  • ❌ “category” (pas de bordure après “cat”)

En savoir plus sur les bordures de mots

Quel est le résultat ?

'banana'.match(/a/g)

Le drapeau g (global) modifie le comportement de match() :

  • Sans g : renvoie la première correspondance avec les groupes de capture
  • Avec g : renvoie un tableau de toutes les chaînes correspondantes

Dans ce cas, il trouve toutes les occurrences de “a” dans “banana”.

Note : si vous avez besoin à la fois de toutes les correspondances ET des groupes de capture, utilisez matchAll() ou la méthode exec() dans une boucle.

En savoir plus sur le drapeau global

Qu’est-ce qui correspond à ce motif ?

'abc123 def456'.match(/(?<!abc)\d+/g)

Le regard arrière négatif (?<!abc) garantit que les chiffres ne sont pas précédés de “abc” :

  • ❌ “123” (précédé de “abc”)
  • ✅ “23” (précédé de “abc1”)
  • ✅ “456” (précédé de “def”)

JavaScript prend en charge les assertions de regard arrière dans les moteurs modernes. Cet exemple utilise un regard arrière de longueur fixe : abc fait toujours trois caractères. Le regard arrière de longueur variable est l’aspect plus délicat propre à chaque moteur.

Remarque : la prise en charge du regard arrière est relativement récente en JavaScript. Consultez la compatibilité des navigateurs si vous devez supporter d’anciens navigateurs.

Que renverra-t-il ?

'2029-12-31'.match(/(\d{4})-(\d{2})-(\d{2})/).slice(1)

Le motif utilise trois groupes capturants :

  1. (\d{4}) capture l’année
  2. (\d{2}) capture le mois
  3. (\d{2}) capture le jour

match() sans le drapeau g renvoie :

  • Index 0 : correspondance complète
  • Index 1+ : groupes capturants

slice(1) est une astuce courante pour ne récupérer que les groupes capturants.

En savoir plus sur les groupes et la capture

Quel sera le résultat de cela ?

"123aBc".match(/^\d+(?![a-z])/ig)

Le look‑ahead négatif (?![a-z]) garantit qu’il n’y a pas de lettres minuscules après les chiffres. Comme la partie “3aBc” contient une lettre minuscule après les chiffres, cette portion ne correspond pas. Ainsi, seule la séquence de départ “12” correspond.

En savoir plus sur le look‑ahead négatif

Qu’est‑ce qui est renvoyé ?

'a,b,c'.split(/(?<=,)/)

Le motif /(?<=,)/ est un look-behind qui correspond après une virgule :

  • a, (après la virgule)
  • b, (après la virgule)
  • c (pas de virgule après)

Le look-behind ne consomme pas la virgule, ainsi la virgule reste attachée au segment précédent dans le résultat du split.

C’est pratique quand on veut diviser une chaîne en se basant sur ce qui la précède sans perdre le(s) caractère(s) de séparation.

En savoir plus sur les assertions look-behind

Qu’est-ce qui correspond ?

'$100'.match(/$\d+/)

Les caractères spéciaux doivent être échappés avec \ pour correspondre littéralement :

  • $ est un caractère spécial (fin de chaîne)
  • Pour faire correspondre un signe dollar littéral, échappez‑le : \$

Caractères courants nécessitant un échappement :

. * + ? ^ $ [ ] \ ( ) { } |

Sans échappement, de nombreux caractères spéciaux ont des significations regex qui ne sont peut‑être pas ce que vous attendez.

En savoir plus sur l’échappement des caractères spéciaux

Qu’est‑ce qui est correspond ?

'$100'.match(/(?<=\$)\d+/)

Le regard arrière positif (?<=\$) garantit que les chiffres sont précédés d’un signe dollar :

  • (?<=\$): regard arrière pour le signe dollar
  • \d+: correspond à un ou plusieurs chiffres

Les assertions de regard arrière ne consomment pas de caractères ; elles ne font que vérifier ce qui se trouve avant. Cela est utile lorsqu’on veut faire correspondre quelque chose en fonction de ce qui le précède sans inclure cette partie.

En savoir plus sur les assertions de regard arrière

Qu’est‑ce qui est capturé ?

'<b>bold</b>'.match(/<b>(.*?)<\/b>/).slice(1)

Le motif utilise la correspondance paresseuse avec *? :

  • <b> : correspond à la balise d’ouverture
  • (.*?) : capture n’importe quels caractères (paresseux)
  • </b> : correspond à la balise de fermeture

Le ? après * rend la correspondance paresseuse, en capturant le moins de caractères possible. Sans ?, ce serait gourmand et capturerait le plus possible.

slice(1) renvoie uniquement le groupe capturé.

En savoir plus sur la correspondance gourmande vs paresseuse

Qu’est-ce qui correspond ?

'😀 🙂'.match(/\p{Emoji}/gu)

Le drapeau u active :

  • les échappements de propriétés Unicode (\p{...})
  • la gestion correcte des paires de substitution

Sans u, les emojis et autres caractères Unicode pourraient ne pas correspondre correctement. Le motif \p{Emoji} correspond aux caractères possédant la propriété Unicode Emoji. Dans cette chaîne, cela signifie les deux pictogrammes emoji.

Remarque : les échappements de propriétés Unicode nécessitent le drapeau u.

En savoir plus sur le mode Unicode

Désolé d’avance ! 😈
Quel mot de passe correspond à ce modèle ?

/^(?=.*[A-Z])(?=.*[a-z])(?=.*\d)(?=.*[!@#$%^&*]).{8,}$/

Ne rédigez jamais rien de ce genre en production ! 😅

Ce modèle utilise plusieurs assertions positives look‑ahead pour imposer :

  • Au moins une lettre majuscule : (?=.*[A-Z])
  • Au moins une lettre minuscule : (?=.*[a-z])
  • Au moins un chiffre : (?=.*\d)
  • Au moins un caractère spécial : (?=.*[!@#$%^&*])
  • Longueur minimale de 8 : .{8,}

Les look‑ahead sont parfaits pour la validation de mots de passe car ils permettent de vérifier plusieurs critères sans consommer de caractères.

En savoir plus sur les modèles de validation de mot de passe

Comment ças’est passé ? 🧐

Les expressions régulières peuvent être une bête à dompter, mais elles sont incroyablement puissantes une fois que vous avez compris le principe (et toutes les nouvelles syntaxes). Continuez à pratiquer, et vous deviendrez un maître du RegEx en un rien de temps ! 🧙‍♂️

Vous cherchez une pause après tout ce RegEx ?
Pftt, rappelez‑vous : pause après les compétences !

Allez à ma salle pour enchaîner d’autres défis ! 💪