在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循环更容易解释。

其他回答

在某些简单的情况下,您可以通过使用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/用于查找单词边界),这已经足够好了。

我还需要一个regexIndexOf函数用于数组,所以我自己编写了一个。然而,我怀疑,这是优化,但我猜它应该工作正常。

Array.prototype.regexIndexOf = function (regex, startpos = 0) {
    len = this.length;
    for(x = startpos; x < len; x++){
        if(typeof this[x] != 'undefined' && (''+this[x]).match(regex)){
            return x;
        }
    }
    return -1;
}

arr = [];
arr.push(null);
arr.push(NaN);
arr[3] = 7;
arr.push('asdf');
arr.push('qwer');
arr.push(9);
arr.push('...');
console.log(arr);
arr.regexIndexOf(/\d/, 4);

在所有建议的解决方案都以这样或那样的方式失败了我的测试之后(编辑:在我写这篇文章之后,一些解决方案被更新以通过测试),我找到了Array的mozilla实现。indexOf和Array.lastIndexOf

我使用这些来实现我的版本的String.prototype.regexIndexOf和String.prototype.regexLastIndexOf如下:

String.prototype.regexIndexOf = function(elt /*, from*/)
  {
    var arr = this.split('');
    var len = arr.length;

    var from = Number(arguments[1]) || 0;
    from = (from < 0) ? Math.ceil(from) : Math.floor(from);
    if (from < 0)
      from += len;

    for (; from < len; from++) {
      if (from in arr && elt.exec(arr[from]) ) 
        return from;
    }
    return -1;
};

String.prototype.regexLastIndexOf = function(elt /*, from*/)
  {
    var arr = this.split('');
    var len = arr.length;

    var from = Number(arguments[1]);
    if (isNaN(from)) {
      from = len - 1;
    } else {
      from = (from < 0) ? Math.ceil(from) : Math.floor(from);
      if (from < 0)
        from += len;
      else if (from >= len)
        from = len - 1;
    }

    for (; from > -1; from--) {
      if (from in arr && elt.exec(arr[from]) )
        return from;
    }
    return -1;
  };

它们似乎通过了我在问题中提供的测试函数。

显然,它们只在正则表达式匹配一个字符时才有效,但这对于我的目的来说已经足够了,因为我将使用它来处理([abc], \s, \W, \D)之类的事情。

我将继续关注这个问题,以防有人提供更好/更快/更干净/更通用的实现,适用于任何正则表达式。

Use:

str.search(regex)

请在这里查看文档。

好吧,因为你只是想匹配字符的位置,regex可能是多余的。

我假设你想要的不是,找到这些字符中的第一个,而是找到这些字符中的第一个。

这当然是一个简单的答案,但做到了你的问题所要做的事情,尽管没有正则表达式部分(因为你没有明确说明为什么它必须是一个正则表达式)

function mIndexOf( str , chars, offset )
{
   var first  = -1; 
   for( var i = 0; i < chars.length;  i++ )
   {
      var p = str.indexOf( chars[i] , offset ); 
      if( p < first || first === -1 )
      {
           first = p;
      }
   }
   return first; 
}
String.prototype.mIndexOf = function( chars, offset )
{
   return mIndexOf( this, chars, offset ); # I'm really averse to monkey patching.  
};
mIndexOf( "hello world", ['a','o','w'], 0 );
>> 4 
mIndexOf( "hello world", ['a'], 0 );
>> -1 
mIndexOf( "hello world", ['a','o','w'], 4 );
>> 4
mIndexOf( "hello world", ['a','o','w'], 5 );
>> 6
mIndexOf( "hello world", ['a','o','w'], 7 );
>> -1 
mIndexOf( "hello world", ['a','o','w','d'], 7 );
>> 10
mIndexOf( "hello world", ['a','o','w','d'], 10 );
>> 10
mIndexOf( "hello world", ['a','o','w','d'], 11 );
>> -1