String.prototype.lastIndexOf() for regular expressions (v2)

Revision 2 of this benchmark created on


Setup

function findFirst(string, regex, startpos) {
    var indexOf = string.substring(startpos || 0).search(regex);
    return (indexOf >= 0) ? (indexOf + (startpos || 0)) : indexOf;
}

function reverseString(str) {
    var newString = "";
    for (var i = str.length - 1; i >= 0; i--) {
        newString += str[i];
    }
    return newString;
}

function findNextRepeatUntilLast(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;
    var result;
    while((result = regex.exec(stringToWorkWith)) != null) {
        lastIndexOf = result.index;
        regex.lastIndex = ++nextStop;
    }
    return lastIndexOf;
}

function matchAllReturnLast(string, regex) {
    const matches = [...string.matchAll(regex)];
    if (matches.length === 0) return -1;
    return matches.at(-1).index;
}


function reverseTextAndFindFirst(string, regex, startpos = 0) {
    return string.length - findFirst(reverseString(string), regex, startpos) - 1;
}

const testString1 = "foo-123-bar-456"
const testString2 = "foo-123"
const testString3 = "---------------"
const testString4 = "foo123bar456"

const regex = /[^\w\d]/

Test runner

Ready to run.

Testing in
TestOps/sec
find one by one until reaching end and return the last match
findNextRepeatUntilLast(testString1, regex);
findNextRepeatUntilLast(testString2, regex);
findNextRepeatUntilLast(testString3, regex);
findNextRepeatUntilLast(testString4, regex);
ready
reverse text and find the first match
reverseTextAndFindFirst(testString1, regex);
reverseTextAndFindFirst(testString2, regex);
reverseTextAndFindFirst(testString3, regex);
reverseTextAndFindFirst(testString4, regex);
ready
find the last match using negative lookahead
const regexLastOccurence = new RegExp(`${regex.source}(?!.*${regex.source})`, regex.flags);

findFirst(testString1, regexLastOccurence);
findFirst(testString2, regexLastOccurence);
findFirst(testString3, regexLastOccurence);
findFirst(testString4, regexLastOccurence);
ready
match all and return the last
const regexGlobal = new RegExp(`${regex.source}`, "g" + (regex.ignoreCase ? "i" : "") + (regex.multiLine ? "m" : ""));

matchAllReturnLast(testString1, regexGlobal);
matchAllReturnLast(testString2, regexGlobal);
matchAllReturnLast(testString3, regexGlobal);
matchAllReturnLast(testString4, regexGlobal);
ready
find the first match (this just for a comparison with a native solution)
findFirst(testString1, regex);
findFirst(testString2, regex);
findFirst(testString3, regex);
findFirst(testString4, regex);

ready

Revisions

You can edit these tests or add more tests to this page by appending /edit to the URL.