How to find indices of all occurrences of one line in another in JavaScript?

I am trying to find the position of all occurrences of a string in another string that is not case sensitive.

For example, given the line:

  I learned to play the Ukulele in Lebanon. 

and le search string, I want to get an array:

 [2, 25, 27, 33] 

Both lines will be variables - i.e. I cannot hard code their values.

I realized that it was a simple task for regular expressions, but trying to find some time, I would be out of luck.

I found this example on how to do this using .indexOf() , but there certainly should be a more concise way to do this?

+76
javascript string regex indexof
Aug 4 '10 at 10:45 a.m.
source share
11 answers
 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); } 

UPDATE

I did not notice in the original question that the search string should be a variable. I wrote another version to deal with this case that uses indexOf , so you are back to where you started. As Wrikken noted in the comments, for this, in the general case with regular expressions, you will need to avoid special regular expression characters, after which I think that solving regular expressions becomes more of a headache than it costs.

 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> 
+128
Aug 04 '10 at 23:05
source share

Here is the regular expression of the free version:

 function indexes(source, find) { if (!source) { return []; } // if find is empty string return all indexes. if (!find) { // or shorter arrow function: // return source.split('').map((_,i) => i); return source.split('').map(function(_, i) { return i; }); } 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") 

EDIT : and if you want to match strings like 'aaaa' and 'aa' to find [0, 2], use this version:

 function indexes(source, find) { if (!source) { return []; } if (!find) { return source.split('').map(function(_, i) { return i; }); } var result = []; var i = 0; while(i < source.length) { if (source.substring(i, i + find.length) == find) { result.push(i); i += find.length; } else { i++; } } return result; } 
+14
Aug 04 '10 at 23:03
source share

Can you do it!

 //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: Learn to write RegExp

In addition, I realized that this is not exactly what you want, since lastIndex tells us that the end of the needle is not the beginning, but it is close - you can push re.lastIndex-needle.length into the result array ...

Edit: add link

The @Tim Down response uses the result object from RegExp.exec (), and all my Javascript resources obscure its use (other than specifying a string). Therefore, when it uses result.index , it is a kind of unnamed matching object. In the exec MDC description, they do describe this object in decent detail.

+11
Aug 04 '10 at 23:03
source share

If you just want to find the position of all matches, I would like to tell you a little 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) 

it may not be applicable if you have RegExp with a variable length, but for some it may be useful.

+2
Dec 19 '17 at 10:05
source share

Use String.prototype.match .

Here is an example from the MDN documents themselves:

 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'] 
0
Jan 12 '17 at 9:56 on
source share

Follow @ jcubic's answer, its solution caused a bit of confusion for my case
For example, var result = indexes('aaaa', 'aa') it will return [0, 1, 2] instead of [0, 2]
So I updated its solution a bit, as shown below, to fit my case.

 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; } 
0
Apr 19 '18 at 7:16
source share

Here is a simple code

 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, [])); 
0
Jul 02 '18 at 8:16
source share

Thanks for all the feedback. I looked through them all and came up with a function that gives the first one the last index of each occurrence of the string 'needle'. I post this here in case it helps someone.

Please note that this is not the same as the initial request just to start each occurrence. It is better suited for my use because you do not need to keep the length of the needle.

 function findRegexIndices(text, needle, caseSensitive){ var needleLen = needle.length, reg = new RegExp(needle, caseSensitive ? 'gi' : 'g'), indices = [], result; while ( (result = reg.exec(text)) ) { indices.push([result.index, result.index + needleLen]); } return indices } 
0
Jun 11 '19 at 14:12
source share

Maybe you like String.split with RegExp, get an array, and then user Array.reduce to calculate Indexof

 var demoStr = "I learned to play the Ukulele in Lebanon."; function getStrPositions(sourceStr){ let indices = [],reg = /(le)/gi,regTest= /le/i; sourceStr.split(reg).reduce((prev,curr)=>{ regTest.test(curr) && indices.push(prev.length) return prev+curr },'') return indices } getStrPositions(demoStr) 
0
Jun 12 '19 at 7:27
source share

the code below will do your job:

 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") 
-one
Aug 28 '14 at 9:31
source share
 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; } 
-2
Feb 27 '13 at 22:22
source share



All Articles