Dans cet article, nous aborderons différentes méthodes qui fonctionnent en profondeur avec des expressions rationnelles (regexps).
str.match(regexp)
La méthode str.match(regexp) trouve les correspondances de lâexpression rationnelle regexp dans la chaîne de texte str.
Elle dispose de 3 options :
-
si lâexpression rationnelle nâà pas de marqueur
g, alors seul la première correspondance est renvoyée sous la forme dâun tableau avec le groupe capturé et ses propriétés : index (indice de la correspondance), et input (chaîne dâentrée équivalent à str):let str = "I love JavaScript"; let result = str.match(/Java(Script)/); alert( result[0] ); // JavaScript (correspondance exacte) alert( result[1] ); // Script (premier groupe capturant) alert( result.length ); // 2 // Additional information: alert( result.index ); // 7 (indice de la chaîne de caractère où à été trouvée la correspondance) alert( result.input ); // I love JavaScript (chaîne sur laquelle a été effectuée la recherche) -
Si la
regexpdispose dâun marqueurg, alors elle retourne un tableau de toutes les correspondances de texte, sans capturer les groupes ou les autres propriétés.let str = "I love JavaScript"; let result = str.match(/Java(Script)/g); alert( result[0] ); // JavaScript alert( result.length ); // 1 -
Sâil nây a pas de correspondance, quâil y ait un marqueur
gou non,nullest renvoyé.Câest une nuance importante. Si il nây a pas de correspondance, nous ne récupérons pas de tableau vide, mais
null. Il nâest pas rare de faire une erreur en oubliant ce détail, e.g.:let str = "I love JavaScript"; let result = str.match(/HTML/); alert(result); // null alert(result.length); // Error: Cannot read property 'length' of nullSi nous voulons que le résultat soit un tableau, nous pouvons écrire de cette façon:
let result = str.match(regexp) || [];
str.matchAll(regexp)
La méthode str.matchAll(regexp) est une variante âamélioréeâ de str.match.
Elle est principalement utilisée pour rechercher toutes les correspondances au sein de chaque groupe.
Il y a 3 différences avec match:
- Elle retourne un objet iterable avec les correspondances au lieu dâun tableau. Nous pouvons le transformer en un tableau classique en utilisant la méthode
Array.from. - Toutes les correspondances sont retournées dans un tableau incluant les groupes capturants (sous le même format que
str.matchsans le marqueurg). - Sâil nây a aucun résultat, il renvoie un objet itérable vide au lieu de
null.
Exemple dâutilisation:
let str = '<h1>Hello, world!</h1>';
let regexp = /<(.*?)>/g;
let matchAll = str.matchAll(regexp);
alert(matchAll); // [object RegExp String Iterator], pas un tableau, mais un itérateur
matchAll = Array.from(matchAll); // maintenant un tableau
let firstMatch = matchAll[0];
alert( firstMatch[0] ); // <h1>
alert( firstMatch[1] ); // h1
alert( firstMatch.index ); // 0
alert( firstMatch.input ); // <h1>Hello, world!</h1>
Si nous utilisons for..of pour boucler sur les résultats de matchAll, alors il nâest pas nécessaire dâutiliser Array.from.
str.split(regexp|substr, limit)
Divise la chaîne de caractères en utilisant la regexp (ou une sous-chaîne de caractères) comme délimiteur.
Nous pouvons utiliser split avec une chaîne de caractères comme ceci :
alert('12-34-56'.split('-')) // array of ['12', '34', '56']
Mais nous pouvons aussi diviser une chaîne de texte en utilisant une expression rationnelle:
alert('12, 34, 56'.split(/,\s*/)) // array of ['12', '34', '56']
str.search(regexp)
La méthode str.search(regexp) renvoie lâindice du premier motif correspondant, ou -1 si aucune correspondance nâest trouvée:
let str = "A drop of ink may make a million think";
alert( str.search( /ink/i ) ); // 10 (indice du premier motif correspondant)
Limitation importante: search renvoie uniquement la première correspondance.
Si nous avons besoin de lâindice ou de plus de correspondances, nous devrions utiliser dâautres méthodes, comme les trouver tous avec str.matchAll(regexp).
str.replace(str|regexp, str|func)
Il sâagit dâune méthode générique pour chercher et remplacer une chaîne de caractères, lâune des plus utiles. Le couteau suisse pour chercher et remplacer.
Nous pouvons lâutiliser sans regexps, pour chercher et remplacer une sous-chaîne de caractères:
// replace a dash by a colon
alert('12-34-56'.replace("-", ":")) // 12:34-56
Toutefois, il y a un piège.
Quand le premier argument de replace est une chaîne de caractères, elle ne remplace que la première occurence.
Vous pouvez constater dans lâexemple ci-dessous que seul le premier "-" est remplacé par ":".
Pour trouver tous les traits dâunions, nous devons utiliser non pas le caractère "-", mais une expression rationnelle /-/g, avec obligatoirement le marqueur g;
// remplace tous les tirets par deux-points
alert( '12-34-56'.replace( /-/g, ":" ) ) // 12:34:56
Le second argument est une chaîne de caractères de remplacement. Nous pouvons utiliser des caractères spéciaux dedans :
| Symbols | Action in the replacement string |
|---|---|
$& |
insère la chaine de caractère en correspondance |
$` |
Insère la partie de la chaîne de caractère qui précède la sous-chaîne en correspondance |
$' |
insère la partie de la chaîne de caractère qui suit la sous-chaîne en correspondance |
$n |
si n est un nombre à 1 ou 2 chiffres, insère la n-ième chaîne de sous-correspondance entre parenthèses, pour plus de détails voir Groupes capturant |
$<name> |
insère la chaîne de caractère du name correspondant à celui entre parenthèse, pour plus de détails voir Groupes capturant |
$$ |
insère un caractère $ |
Par exemple:
let str = "John Smith";
// inverser le prénom et nom de famille
alert(str.replace(/(john) (smith)/i, '$2, $1')) // Smith, John
Si le contexte nécessite un remplacement âintelligentâ, le second argument peut être une fonction.
Elle sera appelée pour chaque correspondance, et la valeur de retour sera insérée comme remplacement.
La fonction est appelée avec des arguments func(match, p1, p2, ..., pn, offset, input, groups):
matchâ La chaîne de caractère en correspondance,p1, p2, ..., pnâ contenu des groupes capturants (sâil y en a),offsetâ indice de la sous-chaîne correspondante,inputâ la chaîne de texte initiale,groupsâ un objet contenant les groupes nommés.
Si la regexp ne comporte pas de parenthèses, alors la fonction ne contient que 3 arguments: func(str, offset, input).
Par exemple, pour convertir les chaînes de caractères correspondantes en majuscule:
let str = "html and css";
let result = str.replace(/html|css/gi, str => str.toUpperCase());
alert(result); // HTML and CSS
Remplace chaque résultat en utilisant son indice dans la chaîne de caractères:
alert("Ho-Ho-ho".replace(/ho/gi, (match, offset) => offset)); // 0-3-6
Dans lâexemple ci-dessous, il y a 2 groupes entre parenthèses. La fonction de remplacement est alors appelée avec 5 arguments: le premier est la correspondance complète, puis chacun des groupes entre parenthèses et enfin (non présent dans lâexemple) lâindice de la correspondance et la chaîne de caractères initiale:
let str = "John Smith";
let result = str.replace(/(\w+) (\w+)/, (match, name, surname) => `${surname}, ${name}`);
alert(result); // Smith, John
Si il y a de nombreux groupes entre parenthèses, il peut être pratique dâutiliser les paramètres du reste pour y accéder:
let str = "John Smith";
let result = str.replace(/(\w+) (\w+)/, (...match) => `${match[2]}, ${match[1]}`);
alert(result); // Smith, John
Ou, si nous utilisons des groupes nommés, alors lâobjet groups est toujours placé en dernier, et nous pouvons lâobtenir de cette façon:
let str = "John Smith";
let result = str.replace(/(?<name>\w+) (?<surname>\w+)/, (...match) => {
let groups = match.pop();
return `${groups.surname}, ${groups.name}`;
});
alert(result); // Smith, John
Les fonctions représentent le pouvoir ultime pour effectuer un remplacement. Elles recupèrent toutes les informations des correspondances, ont accès aux variables externes et sont capable de tout faire.
str.replaceAll(str|regexp, str|func)
This method is essentially the same as str.replace, with two major differences:
- If the first argument is a string, it replaces all occurrences of the string, while
replacereplaces only the first occurrence. - If the first argument is a regular expression without the
gflag, thereâll be an error. Withgflag, it works the same asreplace.
The main use case for replaceAll is replacing all occurrences of a string.
Like this:
// replace all dashes by a colon
alert('12-34-56'.replaceAll("-", ":")) // 12:34:56
regexp.exec(str)
La méthode regexp.exec(str) renvoie une correspondance for regexp dans la chaîne de caractères str. à lâinverse de la méthode précédente, elle est appelée sur une regexp et non une chaîne de caractères.
Elle se comporte différement selon que la regexp dispose dâun marqueur g ou non.
Si g nâest pas présent, alors regexp.exec(str) renvoie la première correspondance tel que le ferait str.match(regexp). Ce comportement nâapporte rien de nouveau.
Mais si g est utilisé, alors:
- Un appel Ã
regexp.exec(str)renvoie la première correspondance et sauvegarde lâindice situé juste après, accessible via la propriétéregexp.lastIndex. - lâappel suivant à la fonction commence la recherche depuis lâindice contenu dans
regexp.lastIndex. La correspondance suivante est renvoyé et lâindice positionné après est sauvegardé dansregexp.lastIndex. - â¦Et ainsi de suite.
- Si aucune correspondance nâest trouvée,
regexp.execrenvoienulletregexp.lastIndexest réinitialisé Ã0.
Donc, un appel répété à cette fonction renvoie toutes les correspondances lâune après lâautre, utilisant la propriété regexp.lastIndex pour se souvenir de lâindice courant à partir duquel la recherche est effectuée.
Avant que la méthode str.matchAll ait été ajoutée à JavaScript, des appels à regexp.exec étaient utilisés dans une boucle afin dâobtenir toutes les correspondances:
let str = 'More about JavaScript at https://javascript.info';
let regexp = /javascript/ig;
let result;
while (result = regexp.exec(str)) {
alert( `Found ${result[0]} at position ${result.index}` );
// Found JavaScript at position 11, puis
// Found javascript at position 33
}
Cela fonctionne également très bien, bien que sur les navigateurs les plus récents str.matchAll est généralement plus pratique.
Nous pouvons utiliser regexp.exec pour rechercher à partir dâun indice donné en réglant manuellement la valeur de lastIndex.
Par exemple:
let str = 'Hello, world!';
let regexp = /\w+/g; // sans le marqueur "g", la propriété lastIndex est ignorée
regexp.lastIndex = 5; // commence la recherche à partir de la 5ème position (à partir de la virgule)
alert( regexp.exec(str) ); // world
Si la regexp utilise le marqueur y, alors la recherche sâeffectuera à lâindice précis de regexp.lastIndex, pas plus loin.
Remplaçons le marqueur g par y dans lâexemple précédent. Aucune correspondance nâest trouvée, car il nây a aucun mot à lâindice 5:
let str = 'Hello, world!';
let regexp = /\w+/y;
regexp.lastIndex = 5; // cherche exactement à l'indice 5
alert( regexp.exec(str) ); // null
Câest pratique dans une situation où nous cherchons uniquement à lire quelque chose au sein dâun texte avec une regexp à un indice spécifique, en occultant le reste.
regexp.test(str)
La méthode regexp.test(str) vérifie quâune correspondance existe et renvoie true/false selon le cas.
Par exemple:
let str = "I love JavaScript";
// Ces deux tests réalisent exactement la même chose
alert( /love/i.test(str) ); // true
alert( str.search(/love/i) != -1 ); // true
Un exemple avec un retour négatif:
let str = "Bla-bla-bla";
alert( /love/i.test(str) ); // false
alert( str.search(/love/i) != -1 ); // false
Si la regexp à le marqueur g, alors regexp.test verifiera la propriété regexp.lastIndex et mettra à jours cette propriété, tout comme regexp.exec.
On peut donc lâutiliser pour effectuer une recherche à partir dâun indice donnée:
let regexp = /love/gi;
let str = "I love JavaScript";
// commence la recherche à partir de l'indice 10:
regexp.lastIndex = 10;
alert( regexp.test(str) ); // false (pas de correspondance)
Appliquer la même expression rationnelle globale sur différentes entrées peut conduire à de mauvais résultats, car lâappel à regexp.test modifie la propriété regexp.lastIndex, par conséquent la recherche sur une autre chaîne de caractères risque dâêtre lancer à partir dâun autre indice que 0.
Par exemple, nous appelons ici regexp.test à deux reprises sur la même chaîne de texte, and le second appel échoue:
let regexp = /javascript/g; // (création d'une nouvelle regexp: regexp.lastIndex=0)
alert( regexp.test("javascript") ); // true (maintenant regexp.lastIndex=10)
alert( regexp.test("javascript") ); // false
Câest exactement parce que regexp.lastIndex nâest pas 0 lors du second test.
Afin de contourner cela, nous pouvons réinitialiser regexp.lastIndex = 0 avant chaque recherche. Ou, au lieu dâappeler la méthode sur une regexp, nous pouvons utiliser les méthodes de lâobjet String str.match/search/..., qui nâutilisent pas lastIndex.
Commentaires
<code>, pour plusieurs lignes â enveloppez-les avec la balise<pre>, pour plus de 10 lignes - utilisez une sandbox (plnkr, jsbin, codepenâ¦)