Pourquoi Expressions régulières (Regex) ?
Les expressions régulières, ou Regex en anglais, sont un outil puissant pour la manipulation et le traitement de chaînes de caractères. Dans un monde où les données textuelles sont omniprésentes, avoir une connaissance approfondie des expressions régulières peut grandement améliorer l'efficacité et la qualité du code.
Un cas d'utilisation concret est la validation de formulaires web. Par exemple, pour s'assurer que un utilisateur entre une adresse e-mail valide, on peut utiliser une expression régulière pour vérifier le format correct :
^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$
Prerequis
Pour suivre ce tutoriel, vous aurez besoin des éléments suivants :
- Connaissances en programmation (JavaScript recommandé)
- Un éditeur de code (VSCode, Sublime Text, etc.)
- Node.js installé (pour les exemples JavaScript)
Vous pouvez installer Node.js via le site officiel : https://nodejs.org/
Concepts fondamentaux
1. Meta-caractères et caractères spéciaux
Les meta-caractères sont des symboles qui ont un sens spécial dans les expressions régulières :
. * + ? ^ $ ( ) [ ] { } | \ /
Exemple :
const regex = /a.b/;
console.log(regex.test('acb')); // true
console.log(regex.test('abc')); // false
2. Groupes et captures
Les groupes sont définis par des parenthèses () et permettent de capturer une partie spécifique d'une chaîne :
const regex = /(\d{3})-(\d{3})-(\d{4})/;
const match = '123-456-7890'.match(regex);
console.log(match[1]); // 123
console.log(match[2]); // 456
console.log(match[3]); // 7890
3. Quantificateurs
Les quantificateurs définissent la fréquence d'apparition des éléments avant eux :
a{3} : apparaît exactement 3 fois
a{2,5} : apparaît entre 2 et 5 fois (inclus)
a* : apparaît 0 ou plusieurs fois
a+ : apparaît 1 ou plusieurs fois
Exemple :
const regex = /\d{3}/;
console.log(regex.test('123')); // true
console.log(regex.test('1234')); // false
4. Classes de caractères
Les classes de caractères permettent de spécifier un ensemble de caractères possibles :
\d : chiffres (0-9)
\w : lettres, chiffres et underscores (_)
\s : espaces blancs (incluant tabulations, retours chariot, etc.)
Exemple :
const regex = /\d{3}-\d{2}-\d{4}/;
console.log(regex.test('123-45-6789')); // true
5. Assertions
Les assertions permettent de spécifier des conditions sans les inclure dans le résultat :
^ : début de la chaîne
$ : fin de la chaîne
\b : mot boundary (frontière entre deux mots)
\B : n'est pas une frontière de mot
Exemple :
const regex = /^Hello/;
console.log(regex.test('Hello, world!')); // true
console.log(regex.test('Goodbye, world!')); // false
Mise en pratique : projet fil rouge
Nous allons construire un mini-projet de gestionnaire de tâches simple. Le but est d'ajouter des tâches à une liste et de les filtrer selon différents critères.
Étape 1 : Création du fichier principal
Créez un fichier app.js :
// app.js
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
let tasks = [];
function addTask(task) {
tasks.push(task);
}
function listTasks() {
console.log('Tasks:');
tasks.forEach((task, index) => {
console.log(`${index + 1}: ${task}`);
});
}
function filterTasks(query) {
return tasks.filter(task => task.match(query));
}
rl.question('Enter a task (or type "exit" to quit): ', input => {
if (input.toLowerCase() === 'exit') {
rl.close();
} else {
addTask(input);
listTasks();
rl.prompt();
}
});
Étape 2 : Ajout de fonctionnalité de filtrage
Modifiez app.js pour ajouter la possibilité de filtrer les tâches :
// app.js
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
let tasks = [];
function addTask(task) {
tasks.push(task);
}
function listTasks() {
console.log('Tasks:');
tasks.forEach((task, index) => {
console.log(`${index + 1}: ${task}`);
});
}
function filterTasks(query) {
return tasks.filter(task => task.match(new RegExp(query, 'i')));
}
rl.question('Enter a task (or type "exit" to quit): ', input => {
if (input.toLowerCase() === 'exit') {
rl.close();
} else {
addTask(input);
listTasks();
rl.question('Filter tasks by keyword (leave blank for all): ', filterInput => {
const filteredTasks = filterTasks(filterInput);
console.log('\nFiltered Tasks:');
filteredTasks.forEach((task, index) => {
console.log(`${index + 1}: ${task}`);
});
rl.prompt();
});
}
});
Étape 3 : Ajout de la possibilité de supprimer des tâches
Modifiez app.js pour ajouter la possibilité de supprimer des tâches :
// app.js
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
let tasks = [];
function addTask(task) {
tasks.push(task);
}
function listTasks() {
console.log('Tasks:');
tasks.forEach((task, index) => {
console.log(`${index + 1}: ${task}`);
});
}
function filterTasks(query) {
return tasks.filter(task => task.match(new RegExp(query, 'i')));
}
function deleteTask(index) {
if (index >= 0 && index < tasks.length) {
tasks.splice(index, 1);
console.log('Task deleted.');
} else {
console.log('Invalid index.');
}
}
rl.question('Enter a task (or type "exit" to quit): ', input => {
if (input.toLowerCase() === 'exit') {
rl.close();
} else {
addTask(input);
listTasks();
rl.question('Filter tasks by keyword (leave blank for all): ', filterInput => {
const filteredTasks = filterTasks(filterInput);
console.log('\nFiltered Tasks:');
filteredTasks.forEach((task, index) => {
console.log(`${index + 1}: ${task}`);
});
rl.question('Enter the task number to delete (or type "exit" to quit): ', deleteInput => {
if (deleteInput.toLowerCase() === 'exit') {
rl.close();
} else {
const index = parseInt(deleteInput) - 1;
deleteTask(index);
listTasks();
rl.prompt();
}
});
});
}
});
Erreurs frequentes et debugging
Erreur 1 : Uncaught SyntaxError: Invalid regular expression
Code incorrect :
const regex = /abc/abc/;
Code correct :
const regex = /abc\/abc/;
Erreur 2 : TypeError: Cannot read property 'match' of null
Code incorrect :
const input = readline.question('Enter a task: ');
const match = input.match(/abc/);
console.log(match);
Code correct :
const input = readline.question('Enter a task: ');
if (input) {
const match = input.match(/abc/);
console.log(match);
} else {
console.log('No input provided.');
}
Erreur 3 : RangeError: Invalid count value
Code incorrect :
const regex = /a{1000}/;
console.log(regex.test('a'.repeat(999))); // true
Code correct :
const regex = /a{1,1000}/;
console.log(regex.test('a'.repeat(999))); // true
Pour aller plus loin
1. Regex en production
Explorez les modules @babel/plugin-proposal-regex-named-groups et @babel/plugin-proposal-unicode-property-escapes pour une utilisation plus avancée des groupes nommés et des propriétés Unicode.
Lien : https://babeljs.io/docs/en/babel-plugin-proposal-regex-named-groups
2. Regex pour les URL
En apprenant les expressions régulières, vous découvrirez comment traiter des URL avec des structures complexes. Lisez le chapitre "Regex for URLs" du livre "Mastering Regular Expressions".
Lien : https://regexone.com/lesson/url_regex
3. Regex pour les dates
Explorez comment utiliser les expressions régulières pour valider et extraire des informations de dates dans des chaînes textuelles.
Défi pratique :
Créez une fonction qui prend une chaîne représentant une date en français (ex: "2023-10-05") et retourne la date sous forme ISO 8601 (ex: "2023-10-05T00:00:00Z"). Utilisez les expressions régulières pour extraire les composants de la date et les réassembler correctement.
function parseFrenchDate(frenchDate) {
// Votre code ici
}
console.log(parseFrenchDate('2023-10-05')); // "2023-10-05T00:00:00Z"
En suivant ce tutoriel, vous devriez être capable de manipuler efficacement les expressions régulières dans différents langages de programmation et de réaliser des projets pratiques comme un gestionnaire de tâches. N'oubliez pas d'exercer régulièrement pour améliorer vos compétences en regex !