Autant que je sache, les groupes de capture nommés en JavaScript n'existent pas. Quelle est la méthode alternative pour obtenir une fonctionnalité similaire?
ECMAScript 2018 introduit groupes de capture nommés dans les expressions rationnelles JavaScript.
Si vous devez prendre en charge des navigateurs plus anciens, vous pouvez tout faire avec des groupes de capture normaux (numérotés) que vous pouvez faire avec des groupes de capture nommés. changements de regex.
Les groupes de capture nommés auxquels je peux penser ne présentent que deux avantages "structurels":
Dans certains types de regex (.NET et JGSoft, autant que je sache), vous pouvez utiliser le même nom pour différents groupes dans votre regex ( voir ici pour un exemple où cela compte ). Mais la plupart des versions regex ne supportent pas cette fonctionnalité de toute façon.
Si vous devez faire référence à des groupes de capture numérotés dans une situation où ils sont entourés de chiffres, vous pouvez rencontrer un problème. Supposons que vous vouliez ajouter un zéro à un chiffre et donc que vous souhaitiez remplacer (\d)
Par $10
. En JavaScript, cela fonctionnera (tant que vous aurez moins de 10 groupes de capture dans votre expression rationnelle), mais Perl pensera que vous recherchez le numéro de référence 10
Au lieu du nombre 1
, Suivi par un 0
. En Perl, vous pouvez utiliser ${1}0
Dans ce cas.
En dehors de cela, les groupes de capture nommés ne sont que du "sucre syntaxique". Il est utile d’utiliser les groupes de capture uniquement lorsque vous en avez vraiment besoin et d’utiliser des groupes non-de capture (?:...)
Dans tous les autres cas.
Le problème le plus important (à mon avis) avec JavaScript est qu’il ne prend pas en charge les expressions rationnelles prolixes, ce qui faciliterait beaucoup la création d’expressions régulières lisibles et complexes.
bibliothèque XRegExp de Steve Levithan résout ces problèmes.
Vous pouvez utiliser XRegExp , une implémentation augmentée, extensible, entre navigateurs, d'expressions régulières, incluant la prise en charge de la syntaxe, des indicateurs et des méthodes supplémentaires:
s
pour que les points correspondent à tous les caractères (mode dotall ou ligne unique) et x
pour les espaces libres et les commentaires (mode étendu).Une autre solution possible: créer un objet contenant les noms de groupe et les index.
var regex = new RegExp("(.*) (.*)");
var regexGroups = { FirstName: 1, LastName: 2 };
Ensuite, utilisez les clés d'objet pour référencer les groupes:
var m = regex.exec("John Smith");
var f = m[regexGroups.FirstName];
Cela améliore la lisibilité/qualité du code en utilisant les résultats de la regex, mais pas la lisibilité de la regex elle-même.
Dans ES6, vous pouvez utiliser un tableau de déstructuration pour capturer vos groupes:
let text = '27 months';
let regex = /(\d+)\s*(days?|months?|years?)/;
let [, count, unit] = regex.exec(text) || [];
// count === '27'
// unit === 'months'
Remarquer:
let
ignore la première valeur du tableau résultant, qui correspond à la chaîne correspondante|| []
après .exec()
empêchera une erreur de déstructuration lorsqu'il n'y a pas de correspondance (car .exec()
renverra null
)Mise à jour: Il a finalement été intégré à JavaScript (ECMAScript 2018)!
Les groupes de capture nommés pourraient très bientôt intégrer JavaScript.
La proposition est déjà à l'étape 3.
Un nom peut être attribué à un groupe de capture entre angular à l'aide de la syntaxe (?<name>...)
, pour tout nom d'identifiant. L’expression régulière d’une date peut alors être écrite sous la forme /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u
. Chaque nom doit être unique et suivre la grammaire de ECMAScript IdentifierName.
Il est possible d'accéder aux groupes nommés à partir des propriétés d'une propriété groups du résultat de l'expression régulière. Des références numérotées aux groupes sont également créées, tout comme pour les groupes non nommés. Par exemple:
let re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u;
let result = re.exec('2015-01-02');
// result.groups.year === '2015';
// result.groups.month === '01';
// result.groups.day === '02';
// result[0] === '2015-01-02';
// result[1] === '2015';
// result[2] === '01';
// result[3] === '02';
Nommer les groupes capturés fournit une chose: moins de confusion avec des expressions régulières complexes.
Cela dépend vraiment de votre cas d'utilisation, mais peut-être qu'une jolie impression de votre regex pourrait vous aider.
Vous pouvez également essayer de définir des constantes pour faire référence à vos groupes capturés.
Les commentaires peuvent alors aussi aider à montrer aux autres lecteurs de votre code ce que vous avez fait.
Pour le reste, je suis d’accord avec la réponse de Tims.
Il existe une bibliothèque node.js appelée named-regexp que vous pouvez utiliser dans vos projets node.js (dans le navigateur en empaquetant la bibliothèque avec browserify ou d'autres scripts d'empaquetage). Cependant, la bibliothèque ne peut pas être utilisée avec des expressions régulières contenant des groupes de capture non nommés.
Si vous comptez les accolades de capture d'ouverture dans votre expression régulière, vous pouvez créer un mappage entre les groupes de capture nommés et les groupes de capture numérotés dans votre expression rationnelle, et vous pouvez mélanger et faire correspondre librement. Il vous suffit de supprimer les noms de groupe avant d'utiliser regex. J'ai écrit trois fonctions qui le démontrent. Voir ce résumé: https://Gist.github.com/gbirke/2cc2370135b665eee3ef
Bien que vous ne puissiez pas faire cela avec Vanilla JavaScript, vous pouvez peut-être utiliser certains Array.prototype
fonctionne comme Array.prototype.reduce
pour transformer les correspondances indexées en désignations nommées en utilisant magic.
De toute évidence, la solution suivante nécessitera que les correspondances se produisent dans l'ordre:
// @text Contains the text to match
// @regex A regular expression object (f.e. /.+/)
// @matchNames An array of literal strings where each item
// is the name of each group
function namedRegexMatch(text, regex, matchNames) {
var matches = regex.exec(text);
return matches.reduce(function(result, match, index) {
if (index > 0)
// This substraction is required because we count
// match indexes from 1, because 0 is the entire matched string
result[matchNames[index - 1]] = match;
return result;
}, {});
}
var myString = "Hello Alex, I am John";
var namedMatches = namedRegexMatch(
myString,
/Hello ([a-z]+), I am ([a-z]+)/i,
["firstPersonName", "secondPersonName"]
);
alert(JSON.stringify(namedMatches));
Comme Tim Pietzcker, ECMAScript 2018 introduit les groupes de capture nommés dans les expressions rationnelles JavaScript. Mais ce que je n'ai pas trouvé dans les réponses ci-dessus, c'est comment utiliser le nommé groupe capturé dans la regex elle-même.
vous pouvez utiliser un groupe capturé nommé avec cette syntaxe: \k<name>
. par exemple
var regexObj = /(?<year>\d{4})-(?<day>\d{2})-(?<month>\d{2}) year is \k<year>/
et comme Forivin dit que vous pouvez utiliser le groupe capturé dans le résultat de l’objet comme suit:
let result = regexObj.exec('2019-28-06 year is 2019');
// result.groups.year === '2019';
// result.groups.month === '06';
// result.groups.day === '28';
var regexObj = /(?<year>\d{4})-(?<day>\d{2})-(?<month>\d{2}) year is \k<year>/mgi;
function check(){
var inp = document.getElementById("tinput").value;
let result = regexObj.exec(inp);
document.getElementById("year").innerHTML = result.groups.year;
document.getElementById("month").innerHTML = result.groups.month;
document.getElementById("day").innerHTML = result.groups.day;
}
td, th{
border: solid 2px #ccc;
}
<input id="tinput" type="text" value="2019-28-06 year is 2019"/>
<br/>
<br/>
<span>Pattern: "(?<year>\d{4})-(?<day>\d{2})-(?<month>\d{2}) year is \k<year>";
<br/>
<br/>
<button onclick="check()">Check!</button>
<br/>
<br/>
<table>
<thead>
<tr>
<th>
<span>Year</span>
</th>
<th>
<span>Month</span>
</th>
<th>
<span>Day</span>
</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<span id="year"></span>
</td>
<td>
<span id="month"></span>
</td>
<td>
<span id="day"></span>
</td>
</tr>
</tbody>
</table>