web-dev-qa-db-fra.com

JavaScript: index vs match lors de la recherche de chaînes?

Mis à part la lisibilité, existe-t-il des différences perceptibles (performances) entre l’utilisation de 

str.indexOf("src") 

et 

str.match(/src/)

Personnellement, je préfère match (et regexp) mais les collègues semblent aller dans le sens inverse. Nous nous demandions si cela importait ...?

MODIFIER:

J'aurais dû dire dès le départ qu'il s'agit de fonctions qui effectueront une correspondance partielle avec une chaîne simple (pour récupérer des identifiants dans les attributs de classe pour JQuery) plutôt que des recherches complètes d'expressions rationnelles avec des caractères génériques, etc.

class='redBorder DisablesGuiClass-2345-2d73-83hf-8293' 

C'est donc la différence entre:

string.indexOf('DisablesGuiClass-');

CONTRE

string.match(/DisablesGuiClass-/)
57
indra

RegExp est en effet plus lent que indexOf (vous pouvez le voir ici ), bien que normalement cela ne devrait pas être un problème. Avec RegExp, vous devez également vous assurer que la chaîne est correctement échappée, ce qui est une chose supplémentaire à considérer.

Mis à part ces deux problèmes, si deux outils font exactement ce dont vous avez besoin, pourquoi ne pas choisir le plus simple?

51
David Tang

Votre comparaison peut ne pas être tout à fait juste. indexOf est utilisé avec des chaînes simples et est donc très rapide; match prend une expression régulière - bien sûr, cela peut être plus lent en comparaison, mais si vous voulez faire un match de regex, vous n'irez pas loin avec indexOf. D'autre part, les moteurs d'expression régulière peuvent être optimisés et leurs performances se sont améliorées au cours des dernières années.

Dans votre cas, où vous cherchez une chaîne textuelle, indexOf devrait suffire. Cependant, il existe toujours une application pour les expressions rationnelles: si vous devez faire correspondre les mots entier et si vous souhaitez éviter de faire correspondre les sous-chaînes, les expressions rationnelles vous donnent des "ancres de limite de mot". Par exemple:

indexOf('bar')

va trouver bar trois fois dans bar, fubar, barmy, alors que

match(/\bbar\b/)

ne correspondra à bar que s'il ne fait pas partie d'un mot plus long.

Comme vous pouvez le constater dans les commentaires, certaines comparaisons ont montré qu'une regex peut être plus rapide que indexOf; si elle est critique en termes de performances, vous devrez peut-être profiler votre code.

19
Tim Pietzcker

Si vous essayez de rechercher des occurrences de sous-chaîne sans tenir compte de la casse, alors match semble être plus rapide qu'une combinaison de indexOf et toLowerCase()

Vérifiez ici - http://jsperf.com/regexp-vs-indexof/152

8
Yogesh Mangaj

Vous demandez si str.indexOf('target') ou str.match(/target/) devrait être préféré. Comme d'autres affiches l'ont suggéré, les cas d'utilisation et les types de retour de ces méthodes sont différents. La première demande "où dans str puis-je d'abord trouver 'target'?" La seconde demande "str correspond-il à l'expression rationnelle et, dans l'affirmative, quels sont tous les éléments correspondants pour les groupes de capture associés?"

Le problème est qu’aucun d’entre eux n’est techniquement conçu pour poser la question plus simple: "la chaîne contient-elle la sous-chaîne?" Il y a quelque chose qui est explicitement conçu pour le faire:

var doesStringContainTarget = /target/.test(str);

Utiliser regex.test(string) présente plusieurs avantages:

  1. Il retourne un booléen, ce qui est important pour vous
  2. Il est plus performant que str.match(/target/) (et ses rivaux str.indexOf('target'))
  3. Si, pour une raison quelconque, str est undefined ou null, vous obtiendrez false (le résultat souhaité) au lieu de lancer une TypeError
6
elreimundo

L'utilisation de indexOf devrait, en théorie, être plus rapide qu'un regex lorsque vous cherchez simplement du texte brut, mais vous devez effectuer vous-même des tests comparatifs si vous vous souciez de la performance.

Si vous préférez match et qu'il est assez rapide pour vos besoins, allez-y.

Pour ce qui en vaut la peine, je suis d’accord avec vos collègues sur ce point: j’utiliserais indexOf lorsque je chercherais une chaîne simple et je n’utiliserais match etc. que lorsque j’ai besoin des fonctionnalités supplémentaires fournies par les expressions régulières.

5
LukeH

La performance indexOf sera à tout le moins légèrement plus rapide que match. Tout se résume à la mise en œuvre spécifique. Pour décider lequel utiliser, posez-vous la question suivante: 

Est-ce qu'un indice entier suffira ou est-ce que je besoin de la fonctionnalité d'un RegExp résultat du match?

4
ChaosPandion

Les valeurs de retour sont différentes

Outre les conséquences sur les performances, qui sont traitées dans d'autres réponses, il est important de noter que les valeurs de retour pour chaque méthode sont différentes. les méthodes ne peuvent donc pas simplement être substituées sans changer également votre logique.

Valeur renvoyée de .indexOf : integer

Index de l'objet String appelant de la première occurrence de la valeur spécifiée, démarrant la recherche à fromIndex.
Retourne -1 si la valeur est introuvable.

Valeur renvoyée de .match : array

Un tableau contenant l'intégralité du résultat de la correspondance et les résultats correspondants capturés entre parenthèses.
Retourne null s'il n'y a pas de correspondance.

Étant donné que .indexOf renvoie 0 si la chaîne d'appel commence avec la valeur spécifiée, un test de vérité simple échouera.

Par exemple:

Étant donné cette classe…

class='DisablesGuiClass-2345-2d73-83hf-8293 redBorder' 

… Les valeurs de retour pour chacune seraient différentes:

//  returns `0`, evaluates to `false`
if (string.indexOf('DisablesGuiClass-')) {
    … // this block is skipped.
}

contre.

//  returns `["DisablesGuiClass-"]`, evaluates to `true`
if (string.match(/DisablesGuiClass-/)) { 
    … // this block is run.
}

La méthode correcte pour exécuter un test de vérité avec le retour de .indexOf consiste à tester contre -1:

if (string.indexOf('DisablesGuiClass-') !== -1) {
//  ^returns `0`                        ^evaluates to `true`
    … // this block is run.
}
3
gfullam

n'oubliez pas qu'Internet Explorer 8 ne comprend pas indexOf. Mais si personne de vos utilisateurs n'utilise ie8 (Google Analytics vous le dirait), omettez cette réponse . solution possible pour corriger ie8: Comment réparer Array indexOf () en JavaScript pour les navigateurs Internet Explorer

0
NoWomenNoCry

utilisez toujours indexOf pour l'existence de sous-chaînes et match uniquement lorsque vous en avez réellement besoin. c'est-à-dire que si vous recherchiez Wordsrc dans une chaîne pouvant également contenir altsrc, alors aString.match(/\bsrc\b/) est en effet plus approprié.

0
Walf

Voici tous les moyens possibles (relativement) de rechercher une chaîne 

// 1. includes (introduit dans ES6) 

var string = "string to search for substring",
    substring = "sea";
string.includes(substring);

// 2. string.indexOf

var string = "string to search for substring",
    substring = "sea";
string.indexOf(substring) !== -1;

// 3. RegExp: test

var string = "string to search for substring",
    expr = /sea/;  // no quotes here
expr.test(string);

// 4. string.match

var string = "string to search for substring",
    expr = "/sea/";
string.match(expr);

// 5. string.search

var string = "string to search for substring",
    expr = "/sea/";
string.search(expr);

Voici une réponse: https://koukia.ca/top-6-ways-to-search-for-a-string-in-javascript-and-performance-benchmarks-ce3e9b81ad31

Les repères semblent être tordus spécialement pour es6 comprend, lisez les commentaires.

En résumé:

si vous n'avez pas besoin des allumettes. => Soit vous avez besoin de regex et utilisez donc test. Sinon es6 inclut ou indexOf. Toujours test vs indexOf sont proches.

Et pour includes vs indexOf:

Ils semblent être les mêmes: https://jsperf.com/array-indexof-vs-includes/4 (si c'était différent, ce serait étrange, ils fonctionnent généralement de la même manière, à l'exception des différences qu'ils exposent vérifie ça )

Et pour mon propre test de référence. le voici http://jsben.ch/fFnA0 Vous pouvez le tester (cela dépend du navigateur) [plusieurs fois] voici comment il s’est comporté (plusieurs exécutions indexOf et comprenant un temps sur l’autre et ils sont proches). Donc, ils sont les mêmes. [ici en utilisant la même plate-forme de test que l'article ci-dessus].

 enter image description here  enter image description here

Et ici pour la version longue (8 fois plus longue) http://jsben.ch/wSBA2

 enter image description here

Testé à la fois chrome et firefox, même chose.

Remarquez que jsben.ch ne gère pas le dépassement de mémoire (ou qu'il limite correctement. Il ne montre aucun message). Le résultat peut donc être erroné si vous ajoutez plus de 8 duplications de texte (8 fonctionnent correctement). Mais la conclusion est que pour un très grand texte, les trois fonctionnent de la même manière Sinon, pour indexOf et includes sont les mêmes et testent un peu plus lentement. ou Peut être identique à ce qu'il semblait en chrome (firefox 60, il est plus lent).

Avis avec jsben.ch: ne paniquez pas si vous obtenez un résultat incohérent. Essayez différentes heures et voyez si elles sont cohérentes ou non. Changer de navigateur, parfois ils se trompent complètement. Bug ou mauvaise gestion de la mémoire. Ou quelque chose.

ex:

 enter image description here

Ici aussi, ma référence sur jsperf (meilleurs détails et gestion des graphiques pour plusieurs navigateurs)

(le dessus est chrome)

texte normalhttps://jsperf.com/indexof-vs-includes-vs-test-2019
resume: includes et indexOf ont les mêmes performances. test plus lent. 

 enter image description here  enter image description here (semble tous les trois effectuer la même chose en chrom)

Texte long (12 fois plus longtemps que la normale) https://jsperf.com/indexof-vs-includes-vs-test-2019-long-text-str/
resume: Tous les trois font la même chose. (chrome et firefox)  enter image description here

très courte chaînehttps://jsperf.com/indexof-vs-includes-vs-test-2019-too-short-string/
resume: includes et indexOf effectuent la même chose et testent plus lentement.

 enter image description here

Remarque: à propos de la référence ci-dessus. Pour la chaîne very short, la version (jsperf) contenait une grosse erreur pour chrome. Voyant à mes yeux. environ 60 échantillons ont été exécutés pour les deux indexOf et incluent de la même manière (répété beaucoup de temps). Et testez un peu moins et si lentement… .. ne vous laissez pas berner par le mauvais graphique. C'est clairement faux. Même travail de test ok pour firefox, c'est sûrement un bug. 

Voici l'illustration: (la première image était le test sur firefox)  enter image description here waaaa. Soudain indexOf est devenu superman. Mais comme je l'ai dit, j'ai fait le test et examiné le nombre d'échantillons, il était d'environ 60. Les deux indexOf et comprend et ils ont effectué la même chose. Un bug sur jspref. Sauf pour celui-ci (peut-être à cause d'un problème lié à la restriction de mémoire), tout le reste était cohérent, cela donne plus de détails. Et vous voyez combien de simples se produisent en temps réel.

CV final

indexOf vs includes => Même performance

test => peut être plus lent pour les chaînes courtes ou le texte. Et pareil pour les textes longs. Et il est logique que le moteur regex ajoute une surcharge. En chrome, il semblait que ça n'avait pas d'importance. 

0
Mohamed Allal