Consider your first pattern:
Let's break it down:
/ a literal string
[0-9A-Za-z_-]+ one or more of
_archive a literal string
/ literal slash again
[0-9]+ one or more digits
$ the end of the string must follow the one or more digits
So basically you want to make #4 and #5 optional. To be more specific, you want either both 4 and 5, or neither 4 nor 5.
This means that you have one
a followed by one or more
b, and that this grouped a/b entity is optional.
Letting a be #4 and b be digits like in #5, we're left with:
This will capture the entire group though, like
php -r "preg_match('~/[0-9A-Za-z_-]+_archive(/([0-9]+))?$~', '/news_archive/5', $m); var_dump($m);"
You can just add another group to remedy that though:
php -r "preg_match('~/[0-9A-Za-z_-]+_archive(/([0-9]+))?$~', '/news_archive/44', $m); var_dump($m);"
You could technically make the outside group a non-capturing group (like
(?:/([0-9]+))?), but I don't think the added complication is worth not grabbing the
/ part too.
(By the way, sorry if you're familiar with regex and you found this excessive. I tend to take a very verbose approach to any regex related question :).)