Description du problème
Une chaîne vide "" apparaît lors de la division d'une chaîne en utilisant la méthode divisée de JavaScript, en particulier lors de l'utilisation d'expressions régulières comme délimiteurs.
Questions connexes
Les expressions régulières JavaScript produisent un groupe de cordes vide lors du regroupement des chaînes?
Dans la question ci-dessus, le questionneur a utilisé l'expression régulière pour diviser la chaîne et généré plusieurs chaînes vides "" et le code est le suivant:
La copie de code est la suivante:
'Zhang sdf quatre méthodes asdf wengf aa33net s'.split (/ ([/ u4e00- / u9fa5] {1}) / gi);
// output ["", "zhang", "sdf", "quatre", "up", "", "loi", "asdf", "weng", "", "", "fen", "aa33", "net", "s"]
Alors, quelle est la raison de ces cordes vides?
Analyse des problèmes
Après avoir cherché sur Google, j'ai constaté qu'il n'y avait pas beaucoup de résultats connexes. Même s'il y en avait, il n'y avait pas beaucoup d'explications détaillées. Je l'ai dit grossièrement, puis j'ai donné un lien vers la spécification ECMAScript. Il semble que si vous voulez connaître la vraie raison, vous ne pouvez mordre la balle et regarder les normes.
Normes connexes
Ensuite, selon la pratique internationale, allez d'abord à la construction standard de la ville d'Ecmascript.
La copie de code est la suivante:
String.prototype.split (séparateur, limite)
Ce chapitre présente en détail les étapes d'exécution de la méthode de division. Si vous êtes intéressé, vous pouvez le lire attentivement étape par étape. Je vais seulement expliquer les étapes liées à la génération de chaînes vides ici. S'il y a des points inappropriés, tout le monde est invité à les mentionner.
Étapes connexes
Étapes partielles pour extraire:
L'étape la plus importante de tout le processus est le 13e cycle, et les principales choses que ce cycle fait est la suivante:
• Définissez les valeurs de P et Q. Les valeurs de P et Q sont les mêmes au début de chaque boucle (cette étape est en dehors de la boucle);
• Appelez la méthode SplitMatch (S, Q, R) pour diviser la chaîne;
• Exécuter différentes branches en fonction des résultats retournés et les branches principales sont des branches;
• La branche est divisée en 8 petites étapes pour remplir le résultat retourné dans le réseau prédéfini A
• Dans ces 8 petites étapes, le but de l'étape 1 est de renvoyer une sous-chaîne de la chaîne d'origine, la position de début est P (incluse) et la position finale est Q (incluse). Remarque: Dans cette étape, une chaîne vide sera générée, et je l'ai marquée comme interceptant la chaîne pour la commodité de la citation ci-dessous.
• Ajouter la sous-chaîne de l'étape précédente pour réparer un
• Les prochaines étapes consistent à mettre à jour les variables pertinentes et à poursuivre la boucle suivante. (Le but de l'étape 7 est de sauver le regroupement de capture dans l'expression régulière dans le tableau A, ce qui n'a rien à voir avec la génération d'une chaîne vide)
SplitMatch (S, Q, R)
Ensuite, nous devons comprendre ce que fait la méthode SplitMatch (S, Q, R). Cette méthode est mentionnée ci-dessous dans la spécification divisée. Ce qu'il fait principalement, c'est effectuer des opérations correspondantes en fonction du type de séparateur:
• Si le délimiteur est de type regexp, appelez la méthode interne de Regexp [[match]] pour correspondre à la chaîne. Si le match échoue, renvoyez l'échec. Sinon, renvoyez un résultat MatchResult.
• Si le délimiteur est une chaîne, le jugement de correspondance est effectué, l'échec est renvoyé et le résultat du type de matchResult est renvoyé avec succès.
MatchResult
Dans les étapes ci-dessus, une variable de type MatchResult est introduite. En recherchant le document, il a été constaté que les variables de ce type ont deux attributs Endindex et captures. La valeur d'Endindex est la position correspondant à la chaîne plus 1. Les captures peuvent être comprises comme un tableau. Lorsque le délimiteur est une expression régulière, les éléments à l'intérieur sont les valeurs capturées par le groupe; Lorsque le délimiteur est une chaîne, c'est un tableau vide.
Suivant
Nous pouvons voir à partir des étapes ci-dessus que la chaîne divisée est générée dans l'étape d'interception de la chaîne (sauf pour la capture de groupe des expressions régulières). Sa fonction consiste à intercepter la chaîne entre le démarrage spécifié (inclus) et la position finale (inclus), alors quand reviendra-t-il ""? Il existe un cas particulier où les valeurs de la position de début et de la position finale sont égales, ce qui n'est qu'une supposition, car la spécification ne donne pas les étapes de spécification pour intercepter la chaîne.
Nous sommes tous venus ici, pourquoi ne pas faire un pas en avant?
J'ai donc essayé de rechercher un code source V8 pour voir si je pouvais trouver une méthode d'implémentation spécifique. J'ai trouvé le code pertinent, lien de code source
Voici quelques-uns d'entre eux:
La copie de code est la suivante:
fonction stringsplitjs (séparateur, limite) {
...
...
// le délimiteur est une chaîne
if (! is_regexp (séparateur)) {
var séparateur_string = to_string_inline (séparateur);
if (limit === 0) return [];
// ECMA-262 dit que si le séparateur n'est pas défini, le résultat doit
// être un tableau de taille 1 contenant la chaîne entière.
if (is_undefined (séparateur)) return [sujet];
var séparateur_length = séparateur_string.length;
// Le séparateur est une chaîne vide, qui renvoie directement le tableau de caractères
if (séparateur_length === 0) Retour% stringToArray (sujet, limite);
var result =% stringsplit (sujet, séparateur_string, limite);
Résultat de retour;
}
if (limit === 0) return [];
// Lorsque le délimiteur est une expression régulière, appelez Stringsplitonregexp
Retour StringsPlitonRegexp (sujet, séparateur, limite, longueur);
}
// plusieurs codes sont omis ici
J'ai trouvé dans le code que lors du remplissage du tableau, la méthode% _Substring sera appelée pour intercepter la chaîne. Malheureusement, je n'ai pas trouvé sa définition pertinente. S'il y a des étudiants qui l'ont trouvé, faites-le moi savoir. Cependant, j'ai constaté que la méthode StringSubstring correspondant à la méthode de sous-chaîne dans JavaScript appellera la méthode% _Substring et renverra le résultat. Ensuite, si 'ABC'.Substring (1,1) renvoie "", cela signifie que la méthode% _Substring reviendra "" lorsque la position de début et la position finale sont les mêmes. Vous pouvez dire le résultat en l'essayant.
Ainsi, quand la position de démarrage est-elle égale à la position finale (c'est-à-dire Q === P)? J'ai suivi les étapes ci-dessus étape par étape et j'ai finalement trouvé:
• Lorsque la chaîne d'origine correspond au délimiteur une fois, immédiatement après, la position suivante de la chaîne S correspond également au délimiteur. Par exemple: 'abbbc'.split (' b '),' abbbc'.split (/ (b) {1} /)
• Un autre cas est qu'un ou plusieurs caractères au début d'une chaîne correspondent au séparateur. Par exemple: 'ABC'.split (' A '),' ABC'.split (/ ab /)
• Il y a un autre cas où une ou plusieurs chaînes à la fin de la chaîne correspondent au délimiteur, et l'étape pertinente est l'étape 14.
Par exemple: 'ABC'.Split (' C '),' ABC'.split (/ BC /)
De plus, lors de l'utilisation d'expressions régulières comme délimiteurs, un non-défini peut apparaître dans le résultat retourné.
Par exemple: 'ABC'.split (/ (d) * /)
Voyons l'exemple au début. Est-ce que cela satisfait les situations ci-dessus?
Hors sujet
C'est la première fois que je lis avec soin les spécifications standard de l'ECMAScript. Le processus de lecture est en effet très douloureux, mais après l'avoir compris, je me sens très heureux. Merci pour cette question et la question de suivi.
Soit dit en passant, lorsqu'une expression régulière est utilisée comme séparateur, le modificateur global G sera ignoré, ce qui est également un gain supplémentaire.