Encontrar todos os índices de um caractere especificado dentro de uma string

Por exemplo, se eu tivesse "scissors" na variável e quisesse saber a posição de todas as ocorrências da letra "s" , deveria imprimir 1, 4, 5, 8

Como posso fazer isso em JavaScript da maneira mais eficiente? Eu não acho que passar pelo todo seja muito eficiente

Um loop simples funciona bem:

 var str = "scissors"; var indices = []; for(var i=0; i 

Agora, você indica que você quer 1,4,5,8. Isso lhe dará 0, 3, 4, 7, pois os índices são baseados em zero. Então você pode adicionar um:

 if (str[i] === "s") indices.push(i+1); 

e agora ele vai te dar o resultado esperado.

Um violino pode ser visto aqui .

Eu não acho que passar pelo todo seja muito eficiente

No que diz respeito ao desempenho, não acho que isso seja algo com que você precise se preocupar seriamente até começar a encontrar problemas.

Aqui está um teste jsPerf comparando várias respostas. No Safari 5.1, o IndexOf executa o melhor. No Chrome 19, o loop for é o mais rápido.

insira a descrição da imagem aqui

Usando o método nativo String.prototype.indexOf para localizar com mais eficiência cada deslocamento.

 function locations(substring,string){ var a=[],i=-1; while((i=string.indexOf(substring,i+1)) >= 0) a.push(i); return a; } console.log(locations("s","scissors")); //-> [0, 3, 4, 7] 

Esta é uma micro-otimização, no entanto. Para um loop simples e conciso que será rápido o suficiente:

 // Produces the indices in reverse order; throw on a .reverse() if you want for (var a=[],i=str.length;i--;) if (str[i]=="s") a.push(i); 

Na verdade, um loop nativo é mais rápido no chrome que usa indexOf !

Gráfico de resultados de desempenho do link

referência

Quando eu fiz benchmarking de tudo, parecia que as expressões regulares eram as melhores, então eu criei

 function indexesOf(string, regex) { var match, indexes = {}; regex = new RegExp(regex); while (match = regex.exec(string)) { if (!indexes[match[0]]) indexes[match[0]] = []; indexes[match[0]].push(match.index); } return indexes; } 

você consegue fazer isso

 indexesOf('ssssss', /s/g); 

que retornaria

 {s: [0,1,2,3,4,5]} 

Eu precisava de uma maneira muito rápida para combinar vários caracteres contra grandes quantidades de texto, por exemplo, você poderia fazer isso

 indexesOf('dddddssssss', /s|d/g); 

e você conseguiria isso

 {d:[0,1,2,3,4], s:[5,6,7,8,9,10]} 

Desta forma, você pode obter todos os índices de seus jogos de uma só vez.

 function charPos(str, char) { return str .split("") .map(function (c, i) { if (c == char) return i; }) .filter(function (v) { return v >= 0; }); } charPos("scissors", "s"); // [0, 3, 4, 7] 

Observe que o JavaScript conta a partir de 0. Adicione +1 a i , se for necessário.

Diversão mais funcional e também mais geral: Isso localiza os índices iniciais de uma substring de qualquer tamanho em uma string

 const length = (x) => x.length const sum = (a, b) => a+b const indexesOf = (substr) => ({ in: (str) => ( str .split(substr) .slice(0, -1) .map(length) .map((_, i, lengths) => ( lengths .slice(0, i+1) .reduce(sum, i*substr.length) )) ) }); console.log(indexesOf('s').in('scissors')); // [0,3,4,7] console.log(indexesOf('and').in('a and b and c')); // [2,8] 
 indices = (c, s) => s .split('') .reduce((a, e, i) => e === c ? a.concat(i) : a, []); indices('?', 'a?g??'); // [1, 3, 4] 

Você provavelmente poderia usar a function match () do javascript também. Você pode criar uma expressão regular e depois passá-la como um parâmetro para a correspondência ().

 stringName.match(/s/g); 

Isso deve retornar uma matriz de toda a ocorrência da letra ‘s’.