2010-08-04 22 views
56

J'essaie de trouver les positions de toutes les occurrences d'une chaîne dans une autre chaîne, insensible à la casse.Comment trouver les index de toutes les occurrences d'une chaîne dans une autre en JavaScript?

Par exemple, compte tenu de la chaîne:

I learned to play the Ukulele in Lebanon.

et la chaîne de recherche le, je veux obtenir le tableau:

[2, 25, 27, 33] 

Les deux chaînes seront variables - à savoir, je ne peux pas hard-code leurs valeurs. J'ai pensé que c'était une tâche facile pour les expressions régulières, mais après avoir lutté pendant un certain temps pour en trouver un qui fonctionnerait, je n'ai pas eu de chance.

J'ai trouvé this example de la façon d'y parvenir en utilisant .indexOf(), mais sûrement il doit y avoir une façon plus concise de le faire?

+2

+1 pour la référence au Liban. – astazed

Répondre

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

MISE À JOUR

J'échoué à repérer dans la question initiale que la chaîne de recherche doit être une variable. J'ai écrit une autre version pour traiter ce cas qui utilise indexOf, donc vous êtes de retour à l'endroit où vous avez commencé. Comme le souligne Wrikken dans les commentaires, pour faire cela dans le cas général avec des expressions régulières, il faudrait échapper des caractères regex spéciaux, et à ce moment-là je pense que la solution regex devient plus un mal de tête que ça en vaut la peine.

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 + "";
<div id="output"></div>

+0

Comment 'le' serait une chaîne de caractères variable ici? Même en utilisant 'new Regexp (str); le danger des caractères spéciaux est caché, cherchant $ 2.50 par exemple. Quelque chose comme 'regex = new Regexp (dynamictring.replace (/ ([\\. + *? \\ [^ \\] $() {} =! <> |:])/G, '\\ $ 1')); 'serait plus proche à mon humble avis. Je ne suis pas sûr si js a un mécanisme d'échappement regex intégré. – Wrikken

+0

'new RegExp (searchStr)' serait le chemin, et oui, dans le cas général, vous auriez à échapper des caractères spéciaux. Cela ne vaut vraiment pas la peine de le faire à moins d'avoir besoin de ce niveau de généralité. –

+0

... ah, je vois: je n'ai pas compris dans la question que le PO avait besoin de ce niveau de généralité. Réécriture ... –

10
 
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") 

+2

+1 pour une solution sans RegEx. – chryss

+0

Merci, jcubic - cela ressemble à une bonne solution. – Bungle

+4

+1. J'ai fait des tests de comparaison avec une solution utilisant Regex. La méthode la plus rapide était celle utilisant Regex: http://jsperf.com/javascript-find-all – StuR

8

Vous pouvez faire cela!

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

Edit: apprendre à épeler RegExp

Aussi, je compris que ce n'est pas exactement ce que vous voulez, comme lastIndex nous dit la fin de l'aiguille pas au début, mais il est proche - vous pouvez pousser re.lastIndex-needle.length dans le tableau des résultats ...

Edit: ajouter lien

La réponse de @Tim Down utilise l'objet de résultat de RegExp.exec(), et toutes mes ressources Javascript glissent sur son utilisation (à part de vous donner la chaîne correspondante). Donc, quand il utilise result.index, c'est une sorte d'objet Match non nommé. Dans le MDC description of exec, ils décrivent réellement cet objet avec des détails décents.

+0

Annnd @Tim Down a le gagnant, ignore moi ... – Ryley

+0

Ha! Merci de contribuer, en tout cas - je l'apprécie! – Bungle

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

} 
-1

le code ci-dessous fera le travail pour vous:

function indexes(source, find) { 
    var result = []; 
    for(i=0;i<str.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("hello, how are you", "ar") 
3

Utilisez String.prototype.match.

Voici un exemple de la documentation se MDN:

var str = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; 
var regexp = /[A-E]/gi; 
var matches_array = str.match(regexp); 

console.log(matches_array); 
// ['A', 'B', 'C', 'D', 'E', 'a', 'b', 'c', 'd', 'e'] 
+0

C'est assez simple. – igaurav

+4

La question est de savoir comment trouver * indices * d'occurrences, pas les occurrences eux-mêmes! – Luckylooke

1

Si vous voulez juste trouver la position de tous les matches que je voudrais vous montrer un petit hack:

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) 

il peut ne pas être applikable si vous avez un RegExp avec une longueur variable, mais pour certains, il pourrait être utile.