1

I am not sure what seems to be the issue but running exec() inside for loop in Javascript(Nodejs, Chrome console, Firefox console) is producing incorrect results. As far as I know, exec() is a synchronous method, called inside a synchronous loop which should produce the expected output.

const FILTER_REGEX = /(\w+)\s+(below|under|lesser than|lower than|above|over|more than|higher than|greater than|equals|equal to|same as|>|<|=)\s+(\d+)/gi;
const searchQuery = "Package Quantity > 50000 Date yearly ListPrice above 100";
const filterMatches = searchQuery.match(FILTER_REGEX) || [];
for(const filterMatch of filterMatches) {
    const filterMatchGroups = FILTER_REGEX.exec(filterMatch);
    console.log(`filterMatch: ${filterMatch}, filterMatchGroups: ${filterMatchGroups}`);
}

Currently, I am getting the following as output, sometimes filterMatchGroups for first string becomes null and gives filterMatchGroups for second one.

filterMatch: Quantity > 50000, filterMatchGroups: Quantity > 50000,Quantity,>,50000
filterMatch: ListPrice above 100, filterMatchGroups: null
PrivateOmega
  • 2,509
  • 1
  • 17
  • 27
  • @CertainPerfomance How is it a duplicate of that question? – PrivateOmega Mar 04 '19 at 04:49
  • 1
    It almost is, but this question is still open. Problem is that your `FILTER_REGEX` is global and has a *state* (the `lastIndex` property). If you ran a new regex every time, output would be as expected. https://jsfiddle.net/fy0p9jbk/ – CertainPerformance Mar 04 '19 at 04:51
  • 1
    https://stackoverflow.com/questions/1520800/why-does-a-regexp-with-global-flag-give-wrong-results – Andreas Mar 04 '19 at 04:52
  • @CertainPerformance Doesn't global identifier mean that it finds all matches rather than stopping at the first one right? Correct me if i am wrong. – PrivateOmega Mar 04 '19 at 04:52
  • 1
    Not when you use `.exec`, which will return the *next* match (until it gets to the end and can find no more matches, and then it'll start over) – CertainPerformance Mar 04 '19 at 04:53
  • @Andreas Thanks, I wasn't aware that it uses last index for the next check also, So I am hoping resetting lastIndex of regex should make it all good. It's like a really good pitfall I would have never realized if I didn't ask. – PrivateOmega Mar 04 '19 at 04:56
  • I generally don't bother with `exec`; it might be a bit of a performance overhead, but I'll generally use `replace` to search for all results instead of `exec` (even as I'm not interested in replacing anything). No pesky state with `replace`. – Amadan Mar 04 '19 at 05:22
  • @Amadan But how do you get groups from replace()? – PrivateOmega Mar 04 '19 at 05:50
  • 1
    You can use `RegExp.lastMatch` (MDN says it has poor cross-browser compatibility, but I haven't seen it fail for me yet); but the standard way would be via [callback parameters](https://jsbin.com/kahivolulo/edit?js,console). – Amadan Mar 04 '19 at 06:06

1 Answers1

0

This should do it.

const FILTER_REGEX = /(\w+)\s+(below|under|lesser than|lower than|above|over|more than|higher than|greater than|equals|equal to|same as|>|<|=)\s+(\d+)/gi;
const searchQuery = "Package Quantity > 50000 Date yearly ListPrice above 100";
const filterMatches = searchQuery.match(FILTER_REGEX) || [];
for(const filterMatch of filterMatches) {
    FILTER_REGEX.lastIndex = 0;
    const filterMatchGroups = FILTER_REGEX.exec(filterMatch);
    console.log(`filterMatch: ${filterMatch}, filterMatchGroups: ${filterMatchGroups}`);
}

The only visible difference is FILTER_REGEX.lastIndex = 0, we have to reset lastIndex property of a Regex if we have to use it again else it would start the regex check from the previously stored lastIndex. Thanks @CertainPerfomance @Andreas for the links and explanation.

Ref: Detailed Explanation

PrivateOmega
  • 2,509
  • 1
  • 17
  • 27