Come trovare gli indici di tutte le occorrenze di una stringa in un’altra in JavaScript?

Sto cercando di trovare le posizioni di tutte le occorrenze di una stringa in un’altra stringa, senza distinzione tra maiuscole e minuscole.

Ad esempio, data la stringa:

  Ho imparato a suonare l'Ukulele in Libano. 

e il le stringa di ricerca, voglio ottenere l’array:

 [2, 25, 27, 33] 

Entrambe le stringhe saranno variabili, cioè non posso codificare i loro valori.

Ho pensato che fosse un compito facile per le espressioni regolari, ma dopo aver lottato per un po ‘per trovarne uno che avrebbe funzionato, non ho avuto fortuna.

Ho trovato questo esempio di come ottenere ciò usando .indexOf() , ma sicuramente ci deve essere un modo più conciso per farlo?

 var str = "I learned to play the Ukulele in Lebanon." var regex = /le/gi, result, indices = []; while ( (result = regex.exec(str)) ) { indices.push(result.index); } 

AGGIORNARE

Non sono riuscito a individuare nella domanda iniziale che la stringa di ricerca deve essere una variabile. Ho scritto un’altra versione per affrontare questo caso che utilizza indexOf , quindi sei tornato al punto in cui hai iniziato. Come indicato da Wrikken nei commenti, per fare ciò nel caso generale con espressioni regolari è necessario sfuggire a caratteri speciali regolari, a quel punto penso che la soluzione regex diventi più di un mal di testa che non ne valga la pena.

 function getIndicesOf(searchStr, str, caseSensitive) { var searchStrLen = searchStr.length; if (searchStrLen == 0) { return []; } var startIndex = 0, index, indices = []; if (!caseSensitive) { str = str.toLowerCase(); searchStr = searchStr.toLowerCase(); } while ((index = str.indexOf(searchStr, startIndex)) > -1) { indices.push(index); startIndex = index + searchStrLen; } return indices; } var indices = getIndicesOf("le", "I learned to play the Ukulele in Lebanon."); document.getElementById("output").innerHTML = indices + ""; 
 
 function indexes(source, find) { var result = []; for (i = 0; i < source.length; ++i) { // If you want to search case insensitive use // if (source.substring(i, i + find.length).toLowerCase() == find) { if (source.substring(i, i + find.length) == find) { result.push(i); } } return result; } indexes("I learned to play the Ukulele in Lebanon.", "le") 

Di sicuro puoi farlo!

 //make a regular expression out of your needle var needle = 'le' var re = new RegExp(needle,'gi'); var haystack = 'I learned to play the Ukulele'; var results = new Array();//this is the results you want while (re.exec(haystack)){ results.push(re.lastIndex); } 

Modifica: impara a scrivere RegExp

Inoltre, ho capito che non è esattamente quello che vuoi, dato che lastIndex ci dice che la fine dell’ago non è l’inizio, ma è vicina – potresti spingere re.lastIndex-needle.length nell’array dei risultati …

Modifica: aggiunta di link

La risposta di @Tim Down utilizza l’object results di RegExp.exec (), e tutte le mie risorse Javascript gloss sul suo utilizzo (oltre a fornire la stringa corrispondente). Quindi, quando usa result.index , è una sorta di Match Object senza nome. Nella descrizione MDC di exec , in realtà descrivono questo object in modo decente.

Usa String.prototype.match .

Ecco un esempio dei documenti MDN stesso:

 var str = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; var regexp = /[AE]/gi; var matches_array = str.match(regexp); console.log(matches_array); // ['A', 'B', 'C', 'D', 'E', 'a', 'b', 'c', 'd', 'e'] 

Se vuoi solo trovare la posizione di tutte le partite, vorrei indicarti un piccolo trucco:

 haystack = 'I learned to play the Ukulele in Lebanon.' needle = 'le' splitOnFound = haystack.split(needle).map(function (culm) { return this.pos += culm.length + needle.length }, {pos: -needle.length}).slice(0, -1) 

potrebbe non essere apprezzabile se hai un RegExp con lunghezza variabile, ma per alcuni potrebbe essere utile.

Segui la risposta di @jcubic, la sua soluzione ha causato una piccola confusione per il mio caso
Ad esempio var result = indexes('aaaa', 'aa') restituirà [0, 1, 2] invece di [0, 2]
Così ho aggiornato un po ‘la sua soluzione come di seguito per abbinare il mio caso

 function indexes(text, subText, caseSensitive) { var _source = text; var _find = subText; if (caseSensitive != true) { _source = _source.toLowerCase(); _find = _find.toLowerCase(); } var result = []; for (var i = 0; i < _source.length;) { if (_source.substring(i, i + _find.length) == _find) { result.push(i); i += _find.length; // found a subText, skip to next position } else { i += 1; } } return result; } 

Ecco un semplice codice

 function getIndexOfSubStr(str, serchToken, preIndex, output){ var result = str.match(serchToken); if(result){ output.push(result.index +preIndex); str=str.substring(result.index+serchToken.length); getIndexOfSubStr(str, serchToken, preIndex, output) } return output; }; var str = "my name is 'xyz' and my school name is 'xyz' and my area name is 'xyz' "; var serchToken ="my"; var preIndex = 0; console.log(getIndexOfSubStr(str, serchToken, preIndex, [])); 
 function countInString(searchFor,searchIn){ var results=0; var a=searchIn.indexOf(searchFor) while(a!=-1){ searchIn=searchIn.slice(a*1+searchFor.length); results++; a=searchIn.indexOf(searchFor); } return results; } 

il codice seguente farà il lavoro per voi:

 function indexes(source, find) { var result = []; for(i=0;i