Ubuntu 225 's Apache 129 links PCRE2 10.46 (apache2ctl -V), so patterns are Perl-style. A few constructs cover nearly every rule: ^ and $; \. for a literal dot (a bare . is any character); [^/]+ for one segment, \d+ for an ID, [a-z0-9-]+ for a slug; (jpe?g|png); ?, *, + and the lazy +?; and a leading !, which applies the rule when the pattern does not match.
RewriteEngine On
RewriteRule ^page\?id=(\d+)$ show.php?m=never [L]
RewriteRule ^page$ show.php?m=path-only [L]
RewriteRule ^docs/(.+?)(?:\.html)?$ show.php?lazy=$1 [L]
RewriteRule ^guide/(.+)(?:\.html)?$ show.php?greedy=$1 [L]
RewriteRule ^img/([^/]+)\.(jpe?g|png|webp)$ show.php?f=$1&ext=$2 [NC,L]$ t '/page?id=5' /docs/intro.html /guide/intro.html /img/Cat.JPG /img/a/b.png
/page?id=5 200 {"m":"path-only"}
/docs/intro.html 200 {"lazy":"intro"}
/guide/intro.html 200 {"greedy":"intro.html"}
/img/Cat.JPG 200 {"f":"Cat","ext":"JPG"}
/img/a/b.png 404The query string is never part of the pattern, so the first rule can never match; test it with RewriteCond %{QUERY_STRING} (RewriteCond). The greedy (.+) swallowed .html because the optional group after it may match nothing, while the lazy (.+?) stopped as early as it could. [^/]+ refused to cross a slash, and [NC] accepted JPG. Try patterns first in pcre2test (package pcre2-utils) or regex101.com (https://regex101.com/ 21,904 ) in PCRE2 mode.