Reputation: 125
I am making an API and I want to implement an option to filter so I want to validate the expression with a regexp. this is the expression send in request.
filter[price] = gt.5 and lt.10
The rules: the first characters represent the operator to be used example:
gt = '>'
ge = '>='
lt = '<'
le = '<='
eq = '='
ne = '<>'
like = 'like'
ilike = 'ilike'
then there is a point to separate the value to be compared and optionally there would be other expression separated by the 'and' or 'or' operators.
This is the regex that I have built
$re = '/([a-z]{2,5}\.[\w0-9]+)(\s)*(?(2)(and|or)\2+([a-z]{2,5}\.[\w0-9]+))/i';
I want to make the regex take as valid the following cases and that I take as invalid any other case different from those
case 1: gt.5 (valid)
case 2: gt.5 and lt.10 (valid)
case 3: gt.5 and lt.10 or eq.5 (valid)
when I test the regex it works for both cases but it also matches for the following cases but these should be considered invalid.
case 4: gt.5lt.10 (should be invalid)
case 5: gt.5and (should be invalid)
case 6: gt.5..lt.10 (should be invalid)
Upvotes: 2
Views: 152
Reputation: 163217
What you might do instead of using an if clause is optionally repeat the second part with the and
and or
to match multiple parts, and use anchors to prevent partial matches.
Note that \w
also matches a digit 0-9. In the example data, there are digits after the dot, so you could just use \d
instead preventing to match gt.5and
^[a-z]{2,5}\.\d+(?:\h+(?:and|or)\h+[a-z]{2,5}\.\d+)*$
You could make the this part [a-z]{2,5}
more precise using an alteration listing all the options (?:g[te]|l[te]eq|ne|i?like)
A more specific variant could be using the alternation, and recurse the subpattern using (?1)
to make it a bit more succinct.
^([gl][te]|eq|ne|i?like)\.\d+(?:\h+(?:and|or)\h+(?1)\.\d+)*$
Explanation
^
Start of string([gl][te]|eq|ne|i?like)
Match any of the alternatives\.\d+
Match 1 .
and 1+ digits(?:
Non capture group
\h+(?:and|or)\h+
Match either and
or or
between 1+ horizontal whitespace chars(?1)\.\d+
Recurse the first subpattern and match .
and 1+ digits)*
Close group and repeat 0+ times to also allow a single gt.5
$
End of stringUpvotes: 2