I need to write a regular expression for my .htacces file that matches the following:
gallery/a-day-like-today
gallery/a-day-like-today/
gallery/a-day-like-today/2-18
gallery/a-day-like-today/2-18/
Basically, the numbers (2-18) represents the month and the day. It could also contain 1 digit like 9-8 (september the 8th)
If there is a date, then both the month and the day are mandatory.
I started doing something but i'm stock. Any ideas how to achieve it?
^gallery/a-day-like-today(?:/(\d{1,12})-(\d{1,31})?)?$
My solution doesn't work because it picks days that are out of the range {1,31}
my htacces looks like this:
RewriteRule ^gallery/a-day-like-today(?:/(\d{1,12})-(\d{1,31})?)?$ gallery/a_day_like_today.php?month=$1&day=$2 [L]
https://regex101.com/r/zkBQSJ/1
CodePudding user response:
From (\d{1,12})
I can tell that you try to do a range check for month 1...12. Your regex actually means a number 1 to 12 digits long. You can do a range check in regex, but it's a bit convoluted, meaning you might want to extract the numbers, and do the range check on the extracted numbers.
Here is a regex solution for your range check for month and day:
const regex = /^gallery\/a-day-like-today(?:\/?|\/([1-9]|1[0-2])-([1-9]|[12][0-9]|3[01])\/?)$/;
[
'gallery/a-day-like-today',
'gallery/a-day-like-today/',
'gallery/a-day-like-today/2-18',
'gallery/a-day-like-today/2-18/',
'gallery/a-day-like-today/12-1/',
'gallery/a-day-like-today/13-1/',
'gallery/a-day-like-today/1-31/',
'gallery/a-day-like-today/1-32/'
].forEach(str => {
let m = str.match(regex);
console.log(str, '==>', m);
});
Output:
gallery/a-day-like-today ==> [
"gallery/a-day-like-today",
undefined,
undefined
]
gallery/a-day-like-today/ ==> [
"gallery/a-day-like-today/",
undefined,
undefined
]
gallery/a-day-like-today/2-18 ==> [
"gallery/a-day-like-today/2-18",
"2",
"18"
]
gallery/a-day-like-today/2-18/ ==> [
"gallery/a-day-like-today/2-18/",
"2",
"18"
]
gallery/a-day-like-today/12-1/ ==> [
"gallery/a-day-like-today/12-1/",
"12",
"1"
]
gallery/a-day-like-today/13-1/ ==> null
gallery/a-day-like-today/1-31/ ==> [
"gallery/a-day-like-today/1-31/",
"1",
"31"
]
gallery/a-day-like-today/1-32/ ==> null
Explanation of regex:
^gallery\/a-day-like-today
-- literal text at beginning of string(?:
-- non-capture group start\/?
-- optional slash
|
-- logical OR\/
-- literal slash(?:[1-9]|1[0-2])
-- capture group 1 for a single digit 1..9, or two digits 10...12-
-- literal dash(?:[1-9]|[12][0-9]|3[01])
-- capture group 2 for a single digit 1..9, or two digits 10...29, or 30...31\/?
-- optional slash)
-- non-capture group end
$
-- end of string
Learn more about regex: https://twiki.org/cgi-bin/view/Codev/TWikiPresentation2018x10x14Regex
CodePudding user response:
This doesn't check if the numbers make sense as a month day, but it's simple so maybe it will work for your case.
gallery/a-day-like-today/?(\d{1,}-\d{1,})?/?
BTW. Why not just check for gallery/a-day-like-today
and not worry about what goes after?
CodePudding user response:
This regex matches all your conditions plus I added more test cases
^gallery/a-day-like-today/{0,1}\d{0,2}-{0,1}\d{0,2}/{0,1}$
https://regex101.com/r/XqcYf6/1
If you want to return the month and day (when present), you can use the regex
^gallery/a-day-like-today/{0,1}(\d{0,2})-{0,1}(\d{0,2})/{0,1}$
https://regex101.com/r/8WYO0t/1
Test cases
gallery/a-day-like-today
gallery/a-day-like-today/
gallery/a-day-like-today/1-1
gallery/a-day-like-today/1-1/
gallery/a-day-like-today/1-31
gallery/a-day-like-today/1-31/
gallery/a-day-like-today/12-1
gallery/a-day-like-today/12-1/
gallery/a-day-like-today/12-31
gallery/a-day-like-today/12-31/
NOTE: This does not check whether the month-day pair are valid, only matches the pattern. For example, /99-99/
would pass but not be a valid month-day pair. You'll have to tell me if this is OK or not.