Cases and desired outputs:
/order/list/edit/1 => true
/order/list/item => false
/order/list/1/item => false
/order/list/1/item/2/edit => false
my current solution:
/order\/list\/(?:(?!item).)/
current output:
/order/list/edit/1 => true
/order/list/item => false
/order/list/1/item => true
/order/list/1/item/2/edit => true
Any idea to solve this problem?
Code to test:
$regex = "/order\/list\/(?:(?!item).)/";
$urls = [
'/order/list/edit/1',
'/order/list/item',
'/order/list/1/item',
'/order/list/1/item/2/edit'
];
echo $regex . '<br>';
foreach ($urls as $url) {
echo (preg_match($regex, $url) ? 'true' : 'false') . " - " . $url . '<br>';
}
the regex should return true for all strings that start with "/order/list/" and have no "item" after that
CodePudding user response:
You're missing a semicolon (:) after the exclamation point (!) in your regex and the asterisk (*) to repeat the check for all subsequent characters. As beautifully explained in this answer, the correct syntax to exclude a word is
(?:(?!:word).)*
Furthermore, to make everything more readable when you use regex to match URLs, I suggest to use a different delimiter, for example you could use the @
. This allows you to write your URL without escaping the slash (just / instead of \/).
I would also recommend to use the Start ^
and End $
characters to make sure that /order/list/
is indeed the first thing in your URL.
Here's the complete regex based on the observations above
@^/order/list/((?!item).)*$@
So in PHP
$regex = "@^/order/list/((?!item).)*$@";
And this will output
true - /order/list/edit/1
false - /order/list/item
false - /order/list/1/item
false - /order/list/1/item/2/edit