Préface
Récemment, j'ai constaté que la performance des régularités en JavaScript à certains endroits est quelque peu différente de celle d'autres langues ou outils, et est relativement alternative. Bien qu'il vous soit presque impossible de les écrire et que vous pouvez difficilement utiliser les règles que j'ai mentionnées ci-dessous, il est bon de les comprendre après tout.
Les exemples de code de cet article sont exécutés dans un environnement JavaScript qui est compatible avec ES5. C'est-à-dire que les performances des versions avant IE9, les versions autour de FX4, etc. sont probablement différentes de ce que j'ai mentionné ci-dessous.
1. Classe de caractères vide
Une classe de caractères qui ne contient aucun [] est appelée une classe empty char class vide. Je crois que vous n'avez jamais entendu d'autres l'appeler parce que dans d'autres langues, cette méthode d'écriture est illégale, et tous les documents et tutoriels ne parlent pas d'une syntaxe illégale. Permettez-moi de démontrer comment les autres langues ou outils signalent cette erreur:
$ echo | grep '[]' grep: inégalé [ou [^ $ echo | SED '/ [] /' SED: -E Expression # 1, caractère 4: Adresse non terminée Expression régulière $ echo | awk '/ [] /' awk: cmd. Ligne: 1: / [] / awk: cmd. Ligne: 1: ^ Regexpawk non terminé: CMD. Ligne: 1: Erreur: inégalée [ou [^: / [] // $ echo | perl -ne '/ [] /' inégalé [en regex; marqué par <- ici dans m / [<- ici] / at -e ligne 1. $ echo | Ruby -ne '/ [] /' - e: 1: vide char-class: / [] / $ python -c 'import re; re.match ("[]", "")' traceback (dernier appel dernier): fichier "<string>", ligne 1, dans le fichier <module> "e: /ypython/lib/re.py", ligne 137, dans le fichier de correspondance _compile (modèle, drapeau). "E: /ypython/lib/re.py", ligne 244, dans _compile Raising Error, v # invalid Expressionsre_Constants.Error: fin inattendue de l'expression régulière Dans JavaScript, la classe de caractères vide est un composant régulier légal, mais son effet est "jamais apparié", c'est-à-dire que tout échouera. Cela équivaut à l'effet d'un (empty negative lookahead)(?!) :
js> "quoi que ce soit / n" .match (/ [] / g) // classe de caractères null, ne correspond jamais à nulljs> "quoi que
De toute évidence, ce genre de chose est inutile en javascript.
2. Négation de la classe de caractères vide
Les classes de caractères négatives qui ne contiennent pas de caractères sont appelées classe de char vide négative ou classe de char négative vide, car ce nom était "auto-créé" et similaire à la classe de caractères vide mentionnée ci-dessus. Cette méthode d'écriture est également illégale dans d'autres langues:
$ echo | grep '[^]' grep: inégalé [ou [^ $ echo | SED '/ [^] /' SED: -E Expression # 1, caractère 5: Adresse non terminée Expression régulière $ echo | awk '/ [^] /' awk: cmd. Ligne: 1: / [^] / awk: cmd. Ligne: 1: ^ Regexpawk non terminé: CMD. Ligne: 1: Erreur: inégalée [ou [^: / [^] // $ echo | perl -ne '/ [^] /' inégalé [en regex; marqué par <- ici dans m / [<- ici ^] / at -e ligne 1. $ echo | Ruby -ne '/ [^] /' - e: 1: vide char-class: / [^] / $ python -c 'importer re; re.match ("[^]", "")' traceback (le dernier appel dernier): fichier "<string>", ligne 1, dans <module> file "e: /ypython/lib/re.py", ligne 137, dans le match de match _COMPILE _COMPILE (Fraphes). "E: /ypython/lib/re.py", ligne 244, dans _compile Raising Error, v # invalid Expressionsre_Constants.Error: fin inattendue de l'expression régulière $ En JavaScript, nier la classe de caractères nuls est un composant régulier légal. Son effet est juste l'opposé de l'effet de la classe de caractères nul. Il peut correspondre à n'importe quel personnage, y compris la nouvelle ligne "/n" , c'est-à-dire qu'elle équivaut à la commune [/s/S] et [/w/W] :
js> "whatever/n".match(/[^]/g) //Neizontal character class, match any character ["w", "h", "a", "t", "e", "v", "e", "r", "/n"]js> "whatever/n".match(/[/s/S]/g) //Complementary character class, match any character ["w", "h", "a", "t", "e", "v", "e", "r", "/ n"]
Il convient de noter qu'il ne peut pas être appelé "régularité de correspondance permanente", car la classe de caractères doit avoir un personnage à correspondre. Si la chaîne cible est vide ou a été consommée par la régularité de gauche, le match échouera, par exemple:
JS> /ABC@^ /
Si vous voulez connaître les vraies "règles de correspondance permanente", vous pouvez consulter un article que j'ai traduit auparavant: les règles "vides"
3. []] et [^]]
Ceci est relativement simple, c'est-à-dire: dans les expressions régulières de Perl et de certaines autres commandes Linux, si la classe de caractères [] contient un support de carré droit immédiatement après []] support carré gauche, le crochet carré droit sera considéré comme un caractère normal, c'est-à-dire qu'il ne peut correspondre qu'à "]". En JavaScript, cette régularité sera reconnue comme une classe de caractères vide suivie d'un crochet droit, et la classe de caractères vide ne correspondra à rien .[^]] est similaire: en JavaScript, il correspond à un caractère arbitraire (classe de caractères nuls négatifs) suivi d'un support carré droit, tel que "a]","b]" , tandis que dans d'autres langues, il correspond à des caractères non].
$ perl -e 'print "]" = ~ / []] /' 1 $ js -e 'print (/ []] /. test ("]"))' false $ perl -e 'print "x" = ~ / [^]] /' 1 $ js -e 'print (/ [^]] /. test ("x"))' false4. $ Point d'ancrage
Certains débutants pensent que $ correspond au personnage de Newline "/n" , qui est une grosse erreur. $ est une affirmation à largeur zéro, il est impossible de correspondre à un vrai caractère, il ne peut égaler qu'une seule position. La différence dont je veux parler se produit en mode non multi-ligne: vous pourriez penser qu'en mode non multi-ligne, ne correspond pas à la position après le dernier personnage? En fait, ce n'est pas si simple. Dans la plupart des autres langues, si le dernier caractère de la chaîne cible est le caractère Newline "/n" , $ correspondra également à la position avant la nouvelle ligne, c'est-à-dire correspondre aux deux positions sur les côtés gauche et droit de la rupture de la ligne à la fin. De nombreuses langues ont deux notations / z et / z. Si vous connaissez la différence entre eux, vous devez comprendre que dans d'autres langues (Perl, Python, PHP, Java, C # ...), $ en mode non multi-ligne est équivalent à / z, tandis que dans JavaScript, $ en mode non-multi-ligne est une nouvelle ligne). Ruby est un cas spécial car il est par défaut en mode multi-lignes. $ en mode multi-ligne correspondra à la position avant chaque nouvelle ligne, et bien sûr, il comprendra également la pause de ligne qui peut apparaître à la fin. Le livre de Yu Sheng "réguliers" parle également de ces points.
$ perl -e 'imprimer "quoi que ce soit / n" = ~ s / $ / remplacer le caractère / rg' // remplacement global quel que soit le caractère // la position avant la rupture de ligne est remplacée par le caractère de remplacement // La position après la rupture de ligne est remplacée par le $ js -e 'imprimer ("quoi que ce soit / n" .replace (/ $ / g, "Remplacer le caractère")' // Remplacement global du monde5. Dot Metacharacter "."
Dans les expressions régulières en JavaScript, le point Metacharacter "." Peut correspondre à tous les caractères à l'exception des terminateurs à quatre lignes (/ RET RETOUR-CARRIAGE, NEWLINE NEWline, / U2028-line Séparateur, séparateur de paragraphe / u2029), tandis que dans d'autres langues communes, la seule ligne Newline / N sera exclue.
6. Citation en avant
Nous savons tous qu'il y a une référence de retour dans un habitué, c'est-à-dire une référence de nombre de barreaux + à la chaîne qui a été apportée dans le groupe de capture précédent. Le but est de correspondre à nouveau ou en tant que résultat de remplacement (/ devient $). Mais il y a un cas particulier que si le groupe de capture référencé n'a pas commencé (le support de gauche est délimité), il utilise la référence arrière, que se passera-t-il? Par exemple, régulier /(/2(a)){2}/ , (a) est le deuxième groupe de capture, mais le résultat correspondant est utilisé sur son côté gauche. Nous savons que les matchs réguliers de gauche à droite. Il s'agit de l'origine de la référence des vioères du titre dans cette section. Ce n'est pas un concept strict. Alors maintenant, vous y réfléchissez, à quoi reviendra le code JavaScript suivant:
js> / (/ 2 (a)) {2} /. exec ("aaa") ???Avant de répondre à cette question, jetons un coup d'œil aux performances dans d'autres langues. De même, dans d'autres langues, l'écriture de cette façon est fondamentalement invalide:
$ echo aaa | grep '(/ 2 (a)) {2}' grep: invalid back référence $ echo aaa | sed -r '/ (/ 2 (a)) {2} /' sed: -e expression # 1, caractère 12: référence de dos illégal $ echo aaa | awk '/ (/ 2 (a)) {2} /' $ echo aaa | perl -ne 'print / (/ 2 (a)) {2} /' $ echo aaa | Ruby -ne 'print $ _ = ~ / (/ 2 (a)) {2} /' $ python -c 'import re; imprimer re.match ("(/ 2 (a)) {2}", "aaa")' AucunIl n'y a pas d'erreur dans AWK car AWK ne prend pas en charge cette backreference, et / 2 est interprétée comme un caractère avec ASCII Code 2. Cependant, il n'y a pas d'erreur dans Perl Ruby Python. Je ne sais pas pourquoi cette conception devrait être apprise par Perl, mais les effets sont les mêmes. Dans ce cas, il est impossible de correspondre avec succès.
Dans JavaScript, non seulement il ne signale pas une erreur, mais il peut également le faire correspondre avec succès. Voyons que la réponse est la même que celle que vous veniez de penser:
js> /(/2(a)) {2 }/.exec("aaa"))"aa "," a "," a "] Pour vous empêcher d'oublier quel est le résultat renvoyé par exec , permettez-moi de dire. Le premier élément est la chaîne de correspondance complète, c'est-à-dire RegExp["$&"] , suivie du contenu de chaque correspondance de groupe de capture, c'est-à-dire, RegExp.$1 et RegExp.$2. Pourquoi le match peut-il réussir? Quel est le processus de correspondance? Ma compréhension est:
Tout d'abord, nous entrons dans le premier groupe de capture (le support gauche le plus gauche), où la première correspondance valide est / 2, mais à ce moment, le deuxième groupe de capture (A) n'a pas encore été au tour, donc la valeur de RegExp.$2 est toujours undefined , donc / 2, un personnage vide sur la gauche de la première corde cible, ou "position", tout comme ^ et d'autres aspects zéro-width. Le fait est que le match réussit. Continuez à aller, puis le deuxième groupe de capture (A) correspond au premier A dans la chaîne cible, et la valeur de RegExp.$2 est également affectée à "A", puis le premier groupe de capture se termine (le plus à droite le plus à droite le plus à droite le plus à droite), la valeur de RegExp.$1 est également "A". Ensuite, il y a le quantificateur {2}, c'est-à-dire, après le premier A dans la chaîne cible, une nouvelle série de correspondance de régulier (/2(a)) est démarrée. Le point clé est ici: la valeur de RegExp.$2 est que la valeur de / 2 correspond ou est-ce la valeur attribuée à la fin du premier tour de correspondance "A". La réponse est: "Non", les valeurs RegExp.$1 et RegExp.$2 seront effacées comme undefined , et / 1 et / 2 seront les mêmes que la première fois, correspondant avec succès à un caractère vide (équivalent à aucun effet, qu'il soit écrit ou non). Le second A dans la chaîne cible est apparié avec succès, et les valeurs de RegExp.$1 et RegExp.$2 deviennent "A" encore une fois, la valeur de RegExp["$&"] devient la chaîne correspondante complète, les deux premiers a: "aa".
Dans les versions antérieures de Firefox (3,6), le remise des quantificateurs ne dégagera pas la valeur du groupe capturé existant, c'est-à-dire, dans le deuxième tour de matchs, / 2 correspondra au second A, ainsi:
js> /(/2(a)) {2 }/.exec("aaa"))"aaaa "," a "]De plus, la fin d'un groupe de capture dépend de la fermeture du support de clôture. Par exemple, / (a / 1) {3} /. Bien que le premier groupe de capture ait commencé à correspondre lorsque / 1 est utilisé, il ne s'est pas encore terminé. Il s'agit également d'une référence avant, donc le match entre / 1 est toujours vide:
js> /(a/1) {3 }/.exec("aaa")_"aaaa "," a "]Un autre exemple:
js> /(?:(f)(O)(O)|(B)(A)(R))* POUR LE
* est un quantificateur. Après le premier cycle de correspondance: 1 $ est "F", 2 $ est "O", 3 $ est "O", 4 $ n'est pas défini, 5 $ undefined et 6 $ sont undefined .
Au début du deuxième cycle de matchs: toutes les valeurs capturées sont réinitialisées à undefined .
Après le deuxième cycle de matchs: 1 $ undefined , 2 $ undefined , 3 $ undefined , 4 $ est "B", 5 $ est "A", et 6 $ est "R".
& est attribué comme "Foobar", et le match se termine.
Résumer
Ce qui précède est l'intégralité du contenu qui résume les différences entre la régularité de JavaScript et d'autres langues. J'espère que le contenu de cet article sera utile à l'étude et au travail de chacun.