在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”);


当前回答

对于具有稀疏匹配的数据,使用字符串。跨浏览器搜索速度最快。它每次迭代都会重新切片字符串:

function lastIndexOfSearch(string, regex, index) {
  if(index === 0 || index)
     string = string.slice(0, Math.max(0,index));
  var idx;
  var offset = -1;
  while ((idx = string.search(regex)) !== -1) {
    offset += idx + 1;
    string = string.slice(idx + 1);
  }
  return offset;
}

对于密集的数据,我做了这个。与执行方法相比,它比较复杂,但对于密集数据,它比我尝试过的其他方法快2-10倍,比公认的解决方案快100倍左右。要点如下:

It calls exec on the regex passed in once to verify there is a match or quit early. I do this using (?= in a similar method, but on IE checking with exec is dramatically faster. It constructs and caches a modified regex in the format '(r).(?!.?r)' The new regex is executed and the results from either that exec, or the first exec, are returned; function lastIndexOfGroupSimple(string, regex, index) { if (index === 0 || index) string = string.slice(0, Math.max(0, index + 1)); regex.lastIndex = 0; var lastRegex, index flags = 'g' + (regex.multiline ? 'm' : '') + (regex.ignoreCase ? 'i' : ''), key = regex.source + '$' + flags, match = regex.exec(string); if (!match) return -1; if (lastIndexOfGroupSimple.cache === undefined) lastIndexOfGroupSimple.cache = {}; lastRegex = lastIndexOfGroupSimple.cache[key]; if (!lastRegex) lastIndexOfGroupSimple.cache[key] = lastRegex = new RegExp('.*(' + regex.source + ')(?!.*?' + regex.source + ')', flags); index = match.index; lastRegex.lastIndex = match.index; return (match = lastRegex.exec(string)) ? lastRegex.lastIndex - match[1].length : index; };

方法的jsPerf

我不明白上面这些测试的目的。需要正则表达式的情况是不可能与调用indexOf进行比较的,我认为这是首先创建该方法的目的。为了让测试通过,使用'xxx+(?!x)'比调整regex迭代的方式更有意义。

其他回答

结合已经提到的一些方法(indexOf显然相当简单),我认为这些函数将达到目的:

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

更新:编辑regexLastIndexOf(),所以它似乎是模仿lastIndexOf()现在。请让我知道它是否仍然失败,在什么情况下。


更新:通过本页评论和我自己的所有测试。当然,这并不意味着它是防弹的。感谢任何反馈。

如果您正在使用RegExp寻找一个非常简单的lastIndex查找,并且不关心它是否完全模仿了lastIndexOf,那么这可能会引起您的注意。

我只是将字符串反向,并从length - 1中减去第一个出现索引。它碰巧通过了我的测试,但我认为长字符串可能会出现性能问题。

interface String {
  reverse(): string;
  lastIndex(regex: RegExp): number;
}

String.prototype.reverse = function(this: string) {
  return this.split("")
    .reverse()
    .join("");
};

String.prototype.lastIndex = function(this: string, regex: RegExp) {
  const exec = regex.exec(this.reverse());
  return exec === null ? -1 : this.length - 1 - exec.index;
};

我使用string .prototype.match(regex),它返回一个字符串数组,所有找到的匹配给定的正则表达式在字符串(更多信息见这里):

function getLastIndex(text, regex, limit = text.length) { const matches = text.match(regex); // no matches found if (!matches) { return -1; } // matches found but first index greater than limit if (text.indexOf(matches[0] + matches[0].length) > limit) { return -1; } // reduce index until smaller than limit let i = matches.length - 1; let index = text.lastIndexOf(matches[i]); while (index > limit && i >= 0) { i--; index = text.lastIndexOf(matches[i]); } return index > limit ? -1 : index; } // expect -1 as first index === 14 console.log(getLastIndex('First Sentence. Last Sentence. Unfinished', /\. /g, 10)); // expect 29 console.log(getLastIndex('First Sentence. Last Sentence. Unfinished', /\. /g));

来自Jason Bunting的regexIndexOf可以更简单地反向,并且仍然支持UTF8字符:

function regexLastIndexOf(string, regex, startpos=0) {
    return text.length - regexIndexOf([...text].reverse().join(""), regex, startpos) - 1;
}

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

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

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