A maneira mais rápida de verificar uma string contém outra substring em JavaScript?

163

Estou trabalhando com um problema de desempenho em JavaScript. Então, eu só quero perguntar: qual é a maneira mais rápida de verificar se uma string contém outra substring (eu só preciso do valor booleano)? Você poderia sugerir sua ideia e ter um exemplo de código de trecho?

Ồinh Hồng Châu
fonte
Você está perguntando sobre uma substring fixa ou precisa de uma expressão regular (estou um pouco confuso com o uso da regextag)?
Tim Pietzcker
Que tal dividir a string em uma matriz em torno do espaço em branco e fazer uma interseção da matriz? stackoverflow.com/questions/1885557/…
giorgio79
jsben.ch/#/aWxtF
EscapeNetscape 21/16

Respostas:

315

Você tem duas possibilidades:

  1. Expressão regular :

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

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

Expressões regulares parecem ser mais rápidas (pelo menos no Chrome 10).

Teste de desempenho - palheiro curto
Teste de desempenho - palheiro longo


Atualização de 2011:

Não se pode dizer com certeza qual método é mais rápido. As diferenças entre os navegadores são enormes. Enquanto no Chrome 10 indexOfparece ser mais rápido, no Safari 5, indexOfé claramente mais lento que qualquer outro método.

Você tem que ver e tentar por si mesmo. Isso depende de suas necessidades. Por exemplo, uma pesquisa que não diferencia maiúsculas de minúsculas é muito mais rápida com expressões regulares.


Atualização 2018:

Apenas para evitar que as pessoas executem os testes, aqui estão os resultados atuais dos navegadores mais comuns, as porcentagens indicam um aumento de desempenho em relação ao próximo resultado mais rápido (que varia entre os navegadores):

Chrome: indexOf (~ 98% mais rápido) <-- wow
Firefox: RegExp em cache (~ 18% mais rápido)
IE11: RegExp em cache (~ 10% mais rápido)
Edge: indexOf (~ 18% mais rápido)
Safari: RegExp em cache (~ 0.4% mais rápido)

Observe que o RegExp em cache é: var r = new RegExp('simple'); var c = r.test(str);ao contrário de:/simple/.test(str)

Felix Kling
fonte
3
Isso pode ser um pouco mais rápido apenas se o texto a pesquisar for conhecido antes (ou seja, não armazenado em uma variável) porque o regex é criado pelo mecanismo JavaScript durante o tempo de análise. Se você quiser procurar por uma seqüência contida em uma variável dentro de outra variável de cadeia, indexOf é o mais rápido, porque você precisa para criar um objeto RegExp e processar a cadeia de escapar caracteres especiais etc.
Stephen Chung
a partir da experiência, indexOf pode ser mais rápido para a busca case-insensitive se você usar .toLowerCase sobre o que você está procurando primeiro
Hayk Saakian
Estou escrevendo um aplicativo do Office 2013, usando a API Javascript do Microsoft Office e indexOfnão funciona. Não sei por que. Usando Regex embora. Este é um caso extremo, mas outros podem ter o mesmo problema.
Andy Mercer
Qualquer razão substr () não é uma das soluções possíveis? Eu acho que é muito mais rápido que a solução RegEx em muitas situações. Eu não sei como ele se compara ao indexOf () (por isso, se você o deixou de fora porque ele sempre apresenta desempenho pior que o indexOf (), tudo bem, talvez adicione uma nota nesse sentido.) EDIT: este link do JSperf mostra algumas informações interessantes resultados. Versão curta: indexOf () é o mais rápido de todos os métodos, mas isso pode variar com base no comprimento da string e em quaisquer padrões repetidos.
22414 das
1
@ Bisonte: você só pode usar substr se você já sabe onde procurar. Eu me concentrei apenas em soluções genéricas.
Felix Kling
17

Isso funciona para você?

string1.indexOf(string2) >= 0

Editar: isso pode não ser mais rápido que um RegExp se a string2 contiver padrões repetidos. Em alguns navegadores, indexOf pode ser muito mais lento que o RegExp. Ver comentários.

Edit 2: RegExp pode ser mais rápido que indexOf quando as strings são muito longas e / ou contêm padrões repetidos. Veja os comentários e a resposta de @ Felix.

Stephen Chung
fonte
mas como isso se compara a outros métodos? É o mais rápido ou é apenas um dos muitos métodos para fazer isso?
Chii
Isso deve ser rápido, pois é implementado pelo próprio JavaScript (ou seja, ele executa código nativo). Qualquer outro método baseado no código JavaScript será mais lento. Se você souber a sequência exata, uma regex pode ser um pouco mais rápida (como o mecanismo JavaScript não precisa percorrer a cadeia de protótipos para encontrar .indexOf).
Stephen Chung
Se você precisar de pesquisa sem distinção entre maiúsculas e minúsculas, definitivamente precisará criar um objeto e chamada RegExp test.
Stephen Chung
3
Acabei de executar um teste no Safari. indexOfé uma magnitude mais lenta que qualquer outro método. Portanto, não se pode dizer qual método é mais rápido. Varia de navegador para navegador.
Felix Kling 14/03
@ Felix, é uma boa observação (nunca confie em nada até que você realmente tente)! Lembro-me vagamente de algo que diz que em strings com muitos padrões repetidos, os regexs devem ter um desempenho mais rápido do que uma simples implementação de comparação de loop, porque os regexs são compilados em máquinas de estado e podem retroceder muito mais rápido que os loops simples - o que sempre deve rastrear para o próximo caractere. +1 por fazer o experimento e divulgar isso!
Stephen Chung
17

O mais rápido

  1. (ES6) inclui
    var string = "olá",
    substring = "lo";
    string.includes (substring);
  1. ES5 e mais velhos indexOf
    var string = "olá",
    substring = "lo";
    string.indexOf (substring)! == -1;

http://jsben.ch/9cwLJ

insira a descrição da imagem aqui

Tính Ngô Quang
fonte
8

No ES6, o includes()método é usado para determinar se uma sequência pode ser encontrada dentro de outra, retornando trueou falseconforme apropriado.

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

Aqui está jsperf entre

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

E

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

Como o resultado mostrado no jsperf, parece que os dois apresentam bom desempenho.

zangw
fonte
Posso usar "regex" dentro, como inclui o argumento? Curtir str.includes("x|y"):; procure os literais "x" ou "y" na mesma chamada.
Ptkato 15/04
@ Patrick, de acordo com o documento de inclusão, você não pode usá regex-lo. Uma solução para sua pergunta,str.includes("x") || str.includes('y')
zangw
Como resultado das melhorias no JavaScript do Chrome 59, indexOfé significativamente mais rápido que includes(acima de 1600% mais rápido). Não está claro como uma diferença de 44 milhões de iterações / s e mais de 777 milhões de i / s afeta o desempenho do mundo real; no entanto, os dispositivos móveis provavelmente se beneficiam o suficiente e indexOfdevem ser a escolha ideal.
Chad Levy
7

Descobri que usar um loop for simples, iterando sobre todos os elementos da string e comparando o charAtdesempenho é mais rápido que indexOfou Regex. O código e a prova estão disponíveis no JSPerf .

ETA: indexOfe charAtambos têm desempenho semelhante no Chrome Mobile, de acordo com os dados do escopo do navegador listados em jsperf.com

wpg4665
fonte
Estranho que uma função feita à mão seja melhor que uma integrada em uma, mas acho que é porque a agulha é apenas um caractere. Ainda assim ...
Moss
Testado no Chrome Mobile 36.0.1985.57 no Apple iPad (iOS 7.1.1). IndexOf é mais rápido. Desculpe
rpax
O @rpax CharAt ainda é significativamente mais rápido em todas as plataformas (com base no histórico do jsperf), exceto no Chrome Mobile, onde o IndexOf e o CharAt apresentam desempenho muito ruim em comparação com o desktop.
precisa saber é o seguinte
1
Gostaria de ver como isso funciona no NodeJS e também não é um bom exemplo, porque você está procurando apenas um caractere versus uma substring.
qodeninja
Esta não é uma resposta válida. Você não está à procura de uma substring, apenas a ocorrência de um único caractere
Henrik Myntti
3

Para encontrar uma string simples, usar o método indexOf () e usar regex é praticamente o mesmo: http://jsperf.com/substring - então escolha qual deles parecer mais fácil de escrever.

Chii
fonte
1

É uma maneira fácil de usar o .match()método para string.

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

Desejo-lhe um bom dia, senhor!

Anton Danilchenko
fonte
4
Não há razão para matchquando existe um testmétodo ... Confira a resposta principal.
Bergi 5/09/2013