5

Is there a javascript string function that search a regex and it will start the search at the end?

If not, what is the fastest and/or cleanest way to search the index of a regex starting from the end?

example of regex:

/<\/?([a-z][a-z0-9]*)\b[^>]*>?/gi
Marl
  • 1,492
  • 2
  • 22
  • 37
  • 1
    [Is there a version of JavaScript's String.indexOf() that allows for regular expressions?](http://stackoverflow.com/a/274094/402037) – Andreas Oct 18 '13 at 09:26

7 Answers7

4

Maybe this can be useful and easier:

str.lastIndexOf(str.match(<your_regex_here>).pop());
  • This does work for the OP's RegExp; so it is correct. For clarity, though, note it won't work with all REs, namely ones with look ahead / behind. e.g. `'xhtml html'.match(/(?<=x)html/g)`. See Andreas's comment on the question for an implementation that handles this correctly. – Codesmith Oct 04 '21 at 17:04
  • This will throw an error if `match()` returns null. Add a conditional or use optional chain operator, e.g.: `str.lastIndexOf(str.match()?.pop());` – thdoan Jul 01 '22 at 08:51
2

Perhaps something like this is suitable for you?

Javascript

function lastIndexOfRx(string, regex) {
    var match = string.match(regex);

    return  match ? string.lastIndexOf(match.slice(-1)) : -1;
}

var rx = /<\/?([a-z][a-z0-9]*)\b[^>]*>?/gi;

console.log(lastIndexOfRx("", rx));
console.log(lastIndexOfRx("<i>it</i><b>bo</b>", rx));

jsFiddle

And just for interest, this function vs the function that you choose to go with. jsperf

This requires that you format your regex correctly for matching exactly the pattern you want and globally (like given in your question), for example /.*(<\/?([a-z][a-z0-9]*)\b[^>]*>?)/i will not work with this function. But what you do get is a function that is clean and fast.

Xotic750
  • 22,914
  • 8
  • 57
  • 79
1

You may create a reverse function like:

function reverse (s) {
  var o = '';
  for (var i = s.length - 1; i >= 0; i--)
    o += s[i];
  return o;
}

and then use

var yourString = reverse("Your string goes here");
var regex = new Regex(your_expression);
var result = yourString.match(regex);

Another idea: if you want to search by word in reverse order then

function reverseWord(s) {
   var o = '';
   var split = s.split(' ');

  for (var i = split.length - 1; i >= 0; i--)
    o += split[i] + ' ';
  return o;
}

var yourString = reverseWord("Your string goes here");
var regex = new Regex(your_expression);
var result = yourString.match(regex);
Snake Eyes
  • 16,287
  • 34
  • 113
  • 221
  • this is workable, but I want to know the index of the last occurrence of the regex directly. If there is no other faster method, then I'll probably take this as an answer – Marl Oct 18 '13 at 09:37
  • The `result` will returns the array, after that you'll need the last item of array. – Snake Eyes Oct 18 '13 at 09:43
1

Andreas gave this from the comment:

https://stackoverflow.com/a/274094/402037

String.prototype.regexLastIndexOf = function(regex, startpos) {
    regex = (regex.global) ? regex : new RegExp(regex.source, "g" + (regex.ignoreCase ? "i" : "") + (regex.multiLine ? "m" : ""));
    if(typeof (startpos) == "undefined") {
        startpos = this.length;
    } else if(startpos < 0) {
        startpos = 0;
    }
    var stringToWorkWith = this.substring(0, startpos + 1);
    var lastIndexOf = -1;
    var nextStop = 0;
    while((result = regex.exec(stringToWorkWith)) != null) {
        lastIndexOf = result.index;
        regex.lastIndex = ++nextStop;
    }
    return lastIndexOf;
}

Which gives the functionality that I need, I tested my regex, and it is successful. So I'll use this

Community
  • 1
  • 1
Marl
  • 1,492
  • 2
  • 22
  • 37
  • This was the answer years ago, but since javascript now supports some functionalities that are missing before, I updated the accepted answer. – Marl Nov 25 '20 at 07:26
0

It depends what you exactly want to search for. You can use string.lastIndexOf or inside the regexp to use $ (end of the string).

Update: try the regexp

/<\/?([a-z][a-z0-9]*)\b[^>]*>?[\w\W]*$/gi
micnic
  • 10,915
  • 5
  • 44
  • 55
  • the problem with lastIndexOf is that regex are not included in the parameter, it only allows strings – Marl Oct 18 '13 at 09:28
  • well, the updated still returns the first instance of the regex using str.search(/<\/?([a-z][a-z0-9]*)\b[^>]*>?[\w\W]*$/gi); – Marl Oct 18 '13 at 09:35
0
var m = text.match(/.*(<\/?([a-z][a-z0-9]*)\b[^>]*>?)/i);
if (m) {
    textFound = m[1];
    position = text.lastIndexOf(textFound);
}

Use .* to skip as much text as posible, capture the text found and search it with lastIndexOf

EDIT:

Well, if text is found, no need to search with lastIndexOf. m[0] contains the full coincidence (including all the initial padding), and m[1] the searched text. So position of found text is m[0].length - m[1].length

var m = text.match(/.*(<\/?([a-z][a-z0-9]*)\b[^>]*>?)/i);
if (m) {
    textFound = m[1];
    position = m[0].length - m[1].length;
}
MC ND
  • 69,615
  • 8
  • 84
  • 126
-1

Assuming you're looking for a string 'token', then you need the position of 'token' that has no other 'token' following until the end of the string.

So you should compose your regex something like that:

$token = 'token';
$re = "/(?:$token)[^(?:$token)]*$/";

This will find your 'token' where no further 'token' can be found until string end. The "(?:" grouping simply makes the group non-storing, slightly speeding up performance and saving memory.

ErnestV
  • 117
  • 1
  • 6