在javascript中,是否有一个string . indexof()的等效,为第一个参数接受正则表达式而不是字符串,同时仍然允许第二个参数?

我需要做点什么

str.indexOf(/[abc]/ , i);

and

str.lastIndexOf(/[abc]/ , i);

虽然String.search()接受regexp作为参数,但它不允许我指定第二个参数!

编辑: 这比我最初想象的要难,所以我写了一个小测试函数来测试所有提供的解决方案……它假设regexIndexOf和regexLastIndexOf已经添加到String对象中。

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

我正在进行如下测试,以确保至少对于一个字符regexp,如果我们使用indexOf,结果是相同的

在 xes 中寻找 a 测试(“xxx”); 测试('axx'); 测试(“xax”); 测试(“XXA”); 测试(“AXA”); 测试(“xaa”); 测试(“AAX”); 测试(“AAA”);


当前回答

对于一个比大多数其他答案更简洁的解决方案,你可能想要使用String.prototype.replace函数,它将在每个检测到的模式上运行一个函数。例如:

let firstIndex = -1;
"the 1st numb3r".replace(/\d/,(p,i) => { firstIndex = i; });
// firstIndex === 4

这对于“last index”的情况特别有用:

let lastIndex = -1;
"the l4st numb3r".replace(/\d/g,(p,i) => { lastIndex = i; });
// lastIndex === 13

在这里,重要的是要包括“g”修饰符,以便对所有发生的情况进行计算。如果没有找到正则表达式,这些版本也会导致-1。

最后,下面是包含起始索引的更通用的函数:

function indexOfRegex(str,regex,start = 0) {
    regex = regex.global ? regex : new RegExp(regex.source,regex.flags + "g");
    let index = -1;
    str.replace(regex,function() {
        const pos = arguments[arguments.length - 2];
        if(index < 0 && pos >= start)
            index = pos;
    });
    return index;
}

function lastIndexOfRegex(str,regex,start = str.length - 1) {
    regex = regex.global ? regex : new RegExp(regex.source,regex.flags + "g");
    let index = -1;
    str.replace(regex,function() {
        const pos = arguments[arguments.length - 2];
        if(pos <= start)
            index = pos;
    });
    return index;
}

这些函数特别避免在开始索引处分割字符串,我认为这在Unicode时代是有风险的。它们不会修改常见Javascript类的原型(尽管您可以自己这么做)。它们接受更多的RegExp标志,例如“u”或“s”以及将来可能添加的任何标志。我发现回调函数比for/while循环更容易解释。

其他回答

你可以使用substr。

str.substr(i).match(/[abc]/);

在某些简单的情况下,您可以通过使用split简化向后搜索。

function regexlast(string,re){
  var tokens=string.split(re);
  return (tokens.length>1)?(string.length-tokens[tokens.length-1].length):null;
}

这有一些严重的问题:

重叠的匹配不会显示出来 返回的索引是匹配的结束,而不是开始(如果你的regex是一个常量,没问题)

但从好的方面来看,它的代码更少。对于一个不能重叠的定长正则表达式(比如/\s\w/用于查找单词边界),这已经足够好了。

String构造函数的实例有一个.search()方法,该方法接受RegExp并返回第一个匹配项的索引。

要从特定位置开始搜索(伪造.indexOf()的第二个参数),可以切掉前i个字符:

str.slice(i).search(/re/)

但这将获得较短字符串的索引(在第一部分被切掉之后),因此如果返回的索引不是-1,则需要将切掉的部分(i)的长度添加到返回的索引中。这将给你原始字符串的索引:

function regexIndexOf(text, re, i) {
    var indexInSuffix = text.slice(i).search(re);
    return indexInSuffix < 0 ? indexInSuffix : indexInSuffix + i;
}

它不是原生的,但您当然可以添加此功能

<script type="text/javascript">

String.prototype.regexIndexOf = function( pattern, startIndex )
{
    startIndex = startIndex || 0;
    var searchResult = this.substr( startIndex ).search( pattern );
    return ( -1 === searchResult ) ? -1 : searchResult + startIndex;
}

String.prototype.regexLastIndexOf = function( pattern, startIndex )
{
    startIndex = startIndex === undefined ? this.length : startIndex;
    var searchResult = this.substr( 0, startIndex ).reverse().regexIndexOf( pattern, 0 );
    return ( -1 === searchResult ) ? -1 : this.length - ++searchResult;
}

String.prototype.reverse = function()
{
    return this.split('').reverse().join('');
}

// Indexes 0123456789
var str = 'caabbccdda';

alert( [
        str.regexIndexOf( /[cd]/, 4 )
    ,   str.regexLastIndexOf( /[cd]/, 4 )
    ,   str.regexIndexOf( /[yz]/, 4 )
    ,   str.regexLastIndexOf( /[yz]/, 4 )
    ,   str.lastIndexOf( 'd', 4 )
    ,   str.regexLastIndexOf( /d/, 4 )
    ,   str.lastIndexOf( 'd' )
    ,   str.regexLastIndexOf( /d/ )
    ]
);

</script>

我没有完全测试这些方法,但到目前为止,它们似乎是有效的。

var mystring = "abc ab a";
var re  = new RegExp("ab"); // any regex here

if ( re.exec(mystring) != null ){ 
   alert("matches"); // true in this case
}

使用标准正则表达式:

var re  = new RegExp("^ab");  // At front
var re  = new RegExp("ab$");  // At end
var re  = new RegExp("ab(c|d)");  // abc or abd