Il modo più veloce per controllare una stringa contiene un'altra sottostringa in JavaScript?


163

Sto lavorando con un problema di prestazioni su JavaScript. Quindi voglio solo chiedere: qual è il modo più veloce per verificare se una stringa contiene un'altra sottostringa (ho solo bisogno del valore booleano)? Potresti suggerire la tua idea e un esempio di codice dello snippet?


Stai chiedendo una sottostringa fissa o hai bisogno di un'espressione regolare (sono un po 'confuso dall'uso del regextag)?
Tim Pietzcker,


Che ne dici di dividere la stringa in un array attorno agli spazi bianchi e fare un'intersezione di array? stackoverflow.com/questions/1885557/...
giorgio79

Risposte:


315

Hai due possibilità:

  1. Espressione regolare :

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

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

Le espressioni regolari sembrano essere più veloci (almeno in Chrome 10).

Test delle prestazioni - pagliaio corto
Test delle prestazioni - pagliaio lungo


Aggiornamento 2011:

Non si può dire con certezza quale metodo sia più veloce. Le differenze tra i browser sono enormi. Mentre in Chrome 10 indexOfsembra essere più veloce, in Safari 5 indexOfè chiaramente più lento di qualsiasi altro metodo.

Devi vedere e provare per te stesso. Dipende dai tuoi bisogni. Ad esempio, una ricerca senza distinzione tra maiuscole e minuscole è molto più veloce con le espressioni regolari.


Aggiornamento 2018:

Solo per salvare le persone dall'esecuzione dei test stessi, ecco i risultati attuali per i browser più comuni, le percentuali indicano un aumento delle prestazioni rispetto al successivo risultato più veloce (che varia tra i browser):

Chrome: indexOf (~ 98% più veloce) <-- wow
Firefox: cache RegExp (~ 18% più veloce)
IE11: cache RegExp (~ 10% più veloce)
Bordo: indexOf (~ 18% più veloce)
Safari: cache RegExp (~ 0,4% più veloce)

Si noti che RegExp memorizzato nella cache è: var r = new RegExp('simple'); var c = r.test(str);al contrario di:/simple/.test(str)


3
Questo può essere un po 'più veloce solo se il testo da cercare è già noto (cioè non memorizzato in una variabile) perché la regex viene creata dal motore JavaScript durante il tempo di analisi. Se vuoi cercare una stringa contenuta in una variabile all'interno di un'altra variabile stringa, indexOf è il più veloce perché dovrai creare un oggetto RegExp ed elaborare la stringa per sfuggire a caratteri speciali ecc.
Stephen Chung

per esperienza, indexOf può essere più veloce per la ricerca senza distinzione tra maiuscole e minuscole se usi .toLowerCase su qualsiasi cosa tu stia cercando per prima
Hayk Saakian,

Sto scrivendo un'app di Office 2013, utilizzando l'API Javascript di Microsoft Office e l'utilizzo indexOfnon funziona. Non sono sicuro del perché. Utilizzando Regex però lo fa. Questo è un caso limite, ma altri potrebbero riscontrare lo stesso problema.
Andy Mercer,

Qualche motivo substr () non è una delle possibili soluzioni? Immagino che sia molto più veloce della soluzione RegEx in molte situazioni. Non so come paragonarlo a indexOf () però (quindi se lo hai lasciato fuori perché funziona sempre peggio di indexOf () allora va bene, forse aggiungi una nota in tal senso.) EDIT: questo link JSperf mostra alcuni interessanti risultati. Versione breve: indexOf () è il più veloce di tutti i metodi, ma questo può variare in base alla lunghezza della stringa e a qualsiasi motivo ripetuto.
Byson,

1
@Bison: puoi usare solo substr se sai già dove cercare. Mi sono concentrato solo su soluzioni generiche.
Felix Kling,

17

Per te funziona?

string1.indexOf(string2) >= 0

Modifica: potrebbe non essere più veloce di un RegExp se string2 contiene pattern ripetuti. Su alcuni browser, indexOf potrebbe essere molto più lento di RegExp. Vedi commenti

Modifica 2: RegExp potrebbe essere più veloce di indexOf quando le stringhe sono molto lunghe e / o contengono schemi ripetuti. Vedi i commenti e la risposta di @Felix.


ma come si confronta con altri metodi? È questo il più veloce o è solo uno dei tanti metodi per farlo?
Chii,

Questo dovrebbe essere veloce poiché è implementato dallo stesso JavaScript (ovvero esegue codice nativo). Qualsiasi altro metodo basato sul codice JavaScript sarà più lento. Se conosci la stringa esatta, un regex potrebbe essere un po 'più veloce (poiché il motore JavaScript non deve percorrere la catena del prototipo per trovare .indexOf).
Stephen Chung,

Se hai bisogno di una ricerca senza distinzione tra maiuscole e minuscole, dovrai sicuramente creare un oggetto RegExp e chiamare test.
Stephen Chung,

3
Ho appena eseguito un test in Safari. indexOfè di una grandezza più lenta di qualsiasi altro metodo. Quindi in realtà non si può dire quale metodo sia più veloce. Varia da browser a browser.
Felix Kling

@Felix, questa è una buona osservazione (non fidarti mai di nulla fino a quando non lo provi tu stesso)! Ricordo vagamente qualcosa che dice in stringhe con molti pattern ripetuti, i regex dovrebbero funzionare più velocemente di una semplice implementazione di confronto di loop perché i regex sono compilati in macchine a stati e può retrocedere molto più rapidamente dei semplici loop - che deve sempre back- traccia al prossimo personaggio. +1 per fare l'esperimento e metterlo in evidenza!
Stephen Chung,

17

Il più veloce

  1. (ES6) include
    var string = "ciao",
    sottostringa = "lo";
    string.includes (substring);
  1. ES5 e indice precedente
    var string = "ciao",
    sottostringa = "lo";
    string.indexOf (sottostringa)! == -1;

http://jsben.ch/9cwLJ

inserisci qui la descrizione dell'immagine


8

In ES6, il includes()metodo viene utilizzato per determinare se una stringa può essere trovata all'interno di un'altra stringa, restituendo trueo falsecome appropriato.

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

Ecco jsperf in mezzo

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

E

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

Come il risultato mostrato in jsperf, sembra che entrambi funzionino bene.


Posso usare "regex" all'interno, come include l'argomento? Come str.includes("x|y"):; cerca i letterali "x" o "y" nella stessa chiamata.
ptkato,

@Patrick, secondo il documento include, non puoi usarlo regex. Una soluzione per la tua domanda,str.includes("x") || str.includes('y')
zangw

Come risultato dei miglioramenti di Chrome 59 JavaScript, indexOfè significativamente più veloce di includes(fino al 1600% più veloce). Non è chiaro in che modo una differenza di 44 milioni di iterazioni / sec e 777+ milioni di i / sec influenzi le prestazioni del mondo reale, tuttavia i dispositivi mobili probabilmente ne beneficiano abbastanza che indexOfdovrebbe essere la scelta ideale.
Chad Levy,

7

Ho scoperto che l'utilizzo di un semplice ciclo for, l'iterazione su tutti gli elementi nella stringa e il confronto con l'operare si charAtesegue più velocemente di indexOfo Regex. Il codice e la prova sono disponibili su JSPerf .

ETA: indexOfed charAtentrambi funzionano allo stesso modo in modo terribile su Chrome Mobile secondo i dati di Browser Scope elencati su jsperf.com


Strano che una funzione fatta a mano sia migliore di una incorporata, ma immagino che ciò sia dovuto al fatto che l'ago è solo un personaggio. Comunque ...
Moss,

Testato su Chrome Mobile 36.0.1985.57 su Apple iPad (iOS 7.1.1). IndexOf è più veloce. Siamo spiacenti
rpax il

@rpax CharAt è ancora significativamente più veloce su tutte le piattaforme (in base alla cronologia di jsperf) ad eccezione di Chrome Mobile, dove sia IndexOf che CharAt si comportano in modo molto scarso rispetto al desktop.
wpg4665,

1
Mi piacerebbe vedere come si comporta in NodeJS e anche questo non è un buon esempio perché stai cercando solo un personaggio contro una sottostringa.
qodeninja,

Questa non è affatto una risposta valida. Non stai cercando una sottostringa, ma solo la presenza di un singolo personaggio
Henrik Myntti

3

Per trovare una stringa semplice, usare il metodo indexOf () e usare regex è praticamente lo stesso: http://jsperf.com/substring - quindi scegli quello che sembra più facile da scrivere.



1

È un modo semplice per utilizzare il .match()metodo per la stringa.

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)));

Ti auguro una buona giornata, signore!


4
Nessun motivo per matchquando esiste un testmetodo ... Dai un'occhiata alla risposta migliore.
Bergi,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.