Is there a version of JavaScript's String.indexOf() that allows for regular expressions?
In javascript, is there an equivalent of String.indexOf() that takes a regular expression instead of a string for the first first parameter while still allowing a second parameter ?
I need to do something like
str.indexOf(/[abc]/ , i);
and
str.lastIndexOf(/[abc]/ , i);
While String.search() takes a regexp as a parameter it does not allow me to specify a second argument!
Edit:
This turned out to be harder than I originally thought so I wrote a small test function to test all the provided solutions... it assumes regexIndexOf and regexLastIndexOf have been added to the String object.
function test (str) {
var i = str.length +2;
while (i--) {
if (str.indexOf('a',i) != str.regexIndexOf(/a/,i))
alert (['failed regexIndexOf ' , str,i , str.indexOf('a',i) , str.regexIndexOf(/a/,i)]) ;
if (str.lastIndexOf('a',i) != str.regexLastIndexOf(/a/,i) )
alert (['failed regexLastIndexOf ' , str,i,str.lastIndexOf('a',i) , str.regexLastIndexOf(/a/,i)]) ;
}
}
and I am testing as follow to make sure that at least for one character regexp, the result is the same as if we used indexOf
//Look for the a among the xes
test('xxx');
test('axx');
test('xax');
test('xxa');
test('axa');
test('xaa');
test('aax');
test('aaa');
Solution 1:
Instances of the String
constructor have a .search()
method which accepts a RegExp and returns the index of the first match.
To start the search from a particular position (faking the second parameter of .indexOf()
) you can slice
off the first i
characters:
str.slice(i).search(/re/)
But this will get the index in the shorter string (after the first part was sliced off) so you'll want to then add the length of the chopped off part (i
) to the returned index if it wasn't -1
. This will give you the index in the original string:
function regexIndexOf(text, re, i) {
var indexInSuffix = text.slice(i).search(re);
return indexInSuffix < 0 ? indexInSuffix : indexInSuffix + i;
}
Solution 2:
Combining a few of the approaches already mentioned (the indexOf is obviously rather simple), I think these are the functions that will do the trick:
function regexIndexOf(string, regex, startpos) {
var indexOf = string.substring(startpos || 0).search(regex);
return (indexOf >= 0) ? (indexOf + (startpos || 0)) : indexOf;
}
function regexLastIndexOf(string, regex, startpos) {
regex = (regex.global) ? regex : new RegExp(regex.source, "g" + (regex.ignoreCase ? "i" : "") + (regex.multiLine ? "m" : ""));
if(typeof (startpos) == "undefined") {
startpos = string.length;
} else if(startpos < 0) {
startpos = 0;
}
var stringToWorkWith = string.substring(0, startpos + 1);
var lastIndexOf = -1;
var nextStop = 0;
while((result = regex.exec(stringToWorkWith)) != null) {
lastIndexOf = result.index;
regex.lastIndex = ++nextStop;
}
return lastIndexOf;
}
UPDATE: Edited regexLastIndexOf()
so that is seems to mimic lastIndexOf()
now. Please let me know if it still fails and under what circumstances.
UPDATE: Passes all tests found on in comments on this page, and my own. Of course, that doesn't mean it's bulletproof. Any feedback appreciated.