Trovare tutti gli indici di un carattere specificato all’interno di una stringa

Per esempio se avessi "scissors" in variabile e volessi sapere la posizione di tutte le occorrenze della lettera "s" , dovrebbe stampare 1, 4, 5, 8

Come posso farlo in JavaScript nel modo più efficiente? Non penso che il ciclo attraverso il tutto sia terribilmente efficiente

Un ciclo semplice funziona bene:

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

Ora indichi che vuoi 1,4,5,8. Questo ti darà 0, 3, 4, 7 poiché gli indici sono a base zero. Quindi potresti aggiungerne uno:

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

e ora ti darà il risultato atteso.

Un violino può essere visto qui .

Non penso che il ciclo attraverso il tutto sia terribilmente efficiente

Per quanto riguarda le prestazioni, non penso che sia qualcosa di cui devi essere seriamente preoccupato fino a quando non inizi a cogliere dei problemi.

Ecco un test jsPerf che confronta varie risposte. In Safari 5.1, IndexOf offre il meglio. In Chrome 19, il ciclo for è il più veloce.

inserisci la descrizione dell'immagine qui

Utilizzando il metodo nativo String.prototype.indexOf per trovare in modo più efficiente ogni offset.

 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] 

Questa è una micro-ottimizzazione, comunque. Per un ciclo semplice e lineare che sarà abbastanza veloce:

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

In effetti, un loop nativo è più veloce su Chrome che usa indexOf !

Grafico dei risultati delle prestazioni dal link

segno di riferimento

Quando ho messo a confronto tutto sembrava che le espressioni regolari fossero le migliori, quindi mi sono inventato questo

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

Puoi farlo

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

che ritornerebbe

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

Avevo bisogno di un modo molto veloce per abbinare più personaggi a grandi quantità di testo, così per esempio si potrebbe fare questo

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

e tu avresti questo

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

in questo modo puoi ottenere tutti gli indici delle tue partite in un colpo solo

 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] 

Nota che JavaScript conta da 0. Aggiungi +1 a i , se necessario.

Divertimento più funzionale e anche più generale: trova gli indici di partenza di una sottostringa di qualsiasi lunghezza in una stringa

 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] 

Probabilmente potresti usare anche la funzione match () di javascript. È ansible creare un’espressione regolare e quindi passarla come parametro alla corrispondenza ().

 stringName.match(/s/g); 

Questo dovrebbe restituirti una matrice di tutte le occorrenze della lettera “s”.