Le moyen le plus rapide de vérifier qu'une chaîne contient une autre sous-chaîne en JavaScript?

163

Je travaille sur un problème de performances sur JavaScript. Donc, je veux juste demander: quel est le moyen le plus rapide de vérifier si une chaîne contient une autre sous-chaîne (j'ai juste besoin de la valeur booléenne)? Pouvez-vous suggérer votre idée et un exemple de code d'extrait?

Đinh Hồng Châu
la source
Vous demandez une sous-chaîne fixe ou avez-vous besoin d'une expression régulière (je suis un peu confus par l'utilisation de la regexbalise)?
Tim Pietzcker
Que diriez-vous de diviser la chaîne en un tableau autour des espaces et de faire une intersection de tableau? stackoverflow.com/questions/1885557/…
giorgio79
jsben.ch/#/aWxtF
EscapeNetscape

Réponses:

315

Vous avez deux possibilités:

  1. Expression régulière :

    (new RegExp('word')).test(str)
    // or
    /word/.test(str)
  2. indexOf:

    str.indexOf('word') !== -1

Les expressions régulières semblent être plus rapides (du moins dans Chrome 10).

Test de performance - Botte de foin courte
Test de performance - Botte de foin longue


Mise à jour 2011:

On ne peut pas dire avec certitude quelle méthode est la plus rapide. Les différences entre les navigateurs sont énormes. Alors que dans Chrome 10 indexOfsemble être plus rapide, dans Safari 5, indexOfc'est clairement plus lent que toute autre méthode.

Vous devez voir et essayer par vous-même. Cela dépend de vos besoins. Par exemple, une recherche insensible à la casse est beaucoup plus rapide avec les expressions régulières.


Mise à jour 2018:

Juste pour éviter aux gens d'exécuter eux-mêmes les tests, voici les résultats actuels pour la plupart des navigateurs courants, les pourcentages indiquent une augmentation des performances par rapport au résultat suivant le plus rapide (qui varie d'un navigateur à l'autre):

Chrome: indexOf (~ 98% plus rapide) <-- wow
Firefox: RegExp mis en cache (~ 18% plus rapide)
IE11: RegExp mis en cache (~ 10% plus rapide)
Edge: indexOf (~ 18% plus rapide)
Safari: RegExp mis en cache (~ 0.4% plus rapide)

Notez que RegExp mis en cache est: var r = new RegExp('simple'); var c = r.test(str);par opposition à:/simple/.test(str)

Félix Kling
la source
3
Cela peut être un peu plus rapide seulement si le texte à rechercher est connu à l'avance (c'est-à-dire qu'il n'est pas stocké dans une variable) car l'expression régulière est créée par le moteur JavaScript pendant le temps d'analyse. Si vous souhaitez rechercher une chaîne contenue dans une variable à l'intérieur d'une autre variable de chaîne, indexOf est le plus rapide car vous auriez besoin de créer un objet RegExp et de traiter la chaîne pour échapper les caractères spéciaux, etc.
Stephen Chung
par expérience, indexOf peut être plus rapide pour la recherche insensible à la casse si vous utilisez .toLowerCase sur tout ce que vous recherchez en premier
Hayk Saakian
J'écris une application Office 2013, en utilisant l'API Javascript Office de Microsoft, et l'utilisation indexOfne fonctionne pas. Je ne sais pas pourquoi. L'utilisation de Regex le fait cependant. Il s'agit d'un cas limite, mais d'autres pourraient rencontrer le même problème.
Andy Mercer
Une raison pour laquelle substr () n'est pas l'une des solutions possibles? Je suppose que c'est beaucoup plus rapide que la solution RegEx dans de nombreuses situations. Je ne sais pas comment cela se compare à indexOf () (donc si vous l'avez laissé de côté parce qu'il fonctionne toujours moins bien que indexOf (), alors c'est bien, ajoutez peut-être une note à cet effet.) EDIT: ce lien JSperf montre des éléments intéressants résultats. Version courte: indexOf () est la plus rapide de toutes les méthodes, mais cela peut varier en fonction de la longueur de la chaîne et des motifs répétitifs.
Byson
1
@Bison: vous ne pouvez utiliser substr que si vous savez déjà où chercher. Je me suis concentré uniquement sur les solutions génériques.
Felix Kling
17

Est-ce que ça marche pour toi?

string1.indexOf(string2) >= 0

Edit: Cela peut ne pas être plus rapide qu'un RegExp si la chaîne2 contient des modèles répétés. Sur certains navigateurs, indexOf peut être beaucoup plus lent que RegExp. Voir les commentaires.

Edit 2: RegExp peut être plus rapide que indexOf lorsque les chaînes sont très longues et / ou contiennent des motifs répétés. Voir les commentaires et la réponse de @ Felix.

Stephen Chung
la source
mais comment cela se compare-t-il aux autres méthodes? Est-ce la méthode la plus rapide ou est-ce simplement l'une des nombreuses méthodes pour y parvenir?
Chii
Cela devrait être rapide car il est implémenté par JavaScript lui-même (c'est-à-dire qu'il exécute du code natif). Toute autre méthode basée sur du code JavaScript sera plus lente. Si vous connaissez la chaîne exacte, une expression régulière peut être un peu plus rapide (car le moteur JavaScript n'a pas à parcourir la chaîne de prototypes pour trouver .indexOf).
Stephen Chung
Si vous avez besoin d'une recherche insensible à la casse, vous devez certainement créer un objet RegExp et appeler test.
Stephen Chung
3
Je viens de lancer un test dans Safari. indexOfest une magnitude plus lente que toute autre méthode. On ne peut donc pas dire quelle méthode est la plus rapide. Cela varie d'un navigateur à l'autre.
Felix Kling
@Felix, c'est une bonne observation (ne faites jamais confiance à rien avant de l'essayer vous-même)! Je me souviens vaguement de quelque chose qui dit dans des chaînes avec beaucoup de modèles répétés, les regex devraient fonctionner plus rapidement qu'une simple implémentation de comparaison de boucles parce que les expressions régulières sont compilées dans des machines à états et elles peuvent revenir en arrière beaucoup plus rapidement que de simples boucles - qui doivent toujours revenir en arrière - suivre le caractère suivant. +1 pour avoir fait l'expérience et l'avoir fait ressortir!
Stephen Chung
17

Le plus rapide

  1. (ES6) comprend
    var string = "bonjour",
    substring = "lo";
    string.includes (sous-chaîne);
  1. ES5 et plus ancien indexOf
    var string = "bonjour",
    substring = "lo";
    string.indexOf (sous-chaîne)! == -1;

http://jsben.ch/9cwLJ

entrez la description de l'image ici

Tính Ngô Quang
la source
8

Dans ES6, la includes()méthode est utilisée pour déterminer si une chaîne peut être trouvée dans une autre chaîne, retournée trueou falseselon le cas.

var str = 'To be, or not to be, that is the question.';

console.log(str.includes('To be'));       // true
console.log(str.includes('question'));    // true
console.log(str.includes('nonexistent')); // false

Voici jsperf entre

var ret = str.includes('one');

Et

var ret = (str.indexOf('one') !== -1);

Comme le résultat montré dans jsperf, il semble que les deux fonctionnent bien.

zangw
la source
Puis-je utiliser "regex" à l'intérieur, comme argument "includes"? Comme str.includes("x|y"):; recherchez les littéraux «x» ou «y» dans le même appel.
ptkato
@Patrick, selon le document d'inclusion, vous ne pouvez pas l'utiliser regex. Un travail autour de votre question,str.includes("x") || str.includes('y')
zangw
À la suite des améliorations de Chrome 59 JavaScript, indexOfest nettement plus rapide que includes(jusqu'à 1600% plus rapide). On ne sait pas comment une différence de 44 millions d'itérations / s et de 777 millions d'itérations / s et plus de 777 millions d' i / s affecte les performances dans le monde réel, mais le mobile en profite suffisamment, ce qui indexOfdevrait être le choix idéal.
Chad Levy
7

J'ai trouvé que l'utilisation d'une simple boucle for, l'itération sur tous les éléments de la chaîne et la comparaison en utilisant sont charAtplus rapides que indexOfou Regex. Le code et la preuve sont disponibles sur JSPerf .

ETA: indexOfet les charAtdeux fonctionnent de manière similaire sur Chrome Mobile selon les données de portée du navigateur répertoriées sur jsperf.com

wpg4665
la source
Etrange qu'une fonction faite à la main soit meilleure qu'une fonction intégrée, mais je suppose que c'est parce que l'aiguille n'est qu'un caractère. Still ...
Moss
Testé dans Chrome Mobile 36.0.1985.57 sur Apple iPad (iOS 7.1.1). IndexOf est plus rapide. Désolé
rpax
@rpax CharAt est encore beaucoup plus rapide sur toutes les plates-formes (basé sur l'historique de jsperf) à l' exception de Chrome Mobile, où IndexOf et CharAt fonctionnent également très mal par rapport au bureau.
wpg4665
1
J'aimerais voir comment cela fonctionne dans NodeJS, et ce n'est pas non plus un bon exemple car vous ne recherchez qu'un caractère par rapport à une sous-chaîne.
qodeninja
Ce n'est pas du tout une réponse valable. Vous ne recherchez pas une sous-chaîne, seulement l'occurrence d'un seul caractère
Henrik Myntti
3

Pour trouver une chaîne simple, utiliser la méthode indexOf () et utiliser regex est à peu près la même chose: http://jsperf.com/substring - choisissez donc celui qui semble le plus facile à écrire.

Chii
la source
1

C'est un moyen facile d'utiliser la .match()méthode pour enchaîner.

var re = /(AND|OR|MAYBE)/;
var str = "IT'S MAYBE BETTER WAY TO USE .MATCH() METHOD TO STRING";
console.log('Do we found something?', Boolean(str.match(re)));

Je vous souhaite une bonne journée, monsieur!

Anton Danilchenko
la source
4
Aucune raison de savoir matchquand il y a une testméthode… Découvrez la réponse principale.
Bergi