19

What is the regex for this?

Match if string

  • NOT ( ends in .php OR ends in .html OR contains / )

Thank you!

Edit: I need the NOT part because the expression is to be used on an Apache mod rewrite, since I can't change the logic of mod_rewrite to avoid the NOT.

Edit: My initial effort was ([^/]+)(\.html)$(^\.php)$ - which is monstrously wrong

Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
johnjohn
  • 4,221
  • 7
  • 36
  • 46

3 Answers3

17

Apache mod_rewrite does support negation, according to this document.

In mod_rewrite, the NOT character ('!') is also available as a possible pattern prefix. This enables you to negate a pattern; to say, for instance: ``if the current URL does NOT match this pattern''. This can be used for exceptional cases, where it is easier to match the negative pattern, or as a last default rule.

So you should be able to do something like:

!^(.*?/.*|.*?\.(?:php|html)$)$

And that should match anything which does not contain / and does not end in .php or .html

Peter Boughton
  • 110,170
  • 32
  • 120
  • 176
  • Fantastic! Thank you very much. I was not aware of the ! feature. Hopefuly, I 'll ask in a better way next time. – johnjohn Jul 27 '10 at 17:08
  • Is it possible to add this as variable now ? I tried RewriteRule !^(.*?/.*|.*?\.(?:php|html)$)$ headers.php?a=$1 [NC,L] but it won't pass the variable – johnjohn Jul 27 '10 at 17:20
  • I guess since you're going a negative match, there's no direct way for the group to match, since you're matching things that might not match the group, so we need a non-negated match which excludes what you want. I can't remember if mod_rewrite supports negative lookbehind, but try this `RewriteRule ^([^/]*(?<!\.html$)(?<!\.php$))$ headers.php?a=$1 [NC,L]` and see if it works? – Peter Boughton Jul 28 '10 at 09:55
5

It's a whole lot easier to do positive matches in regex than negative matches. Try searching for ends in .php OR ends in .html OR contains / and reverse the logic in your program.

With strict regular expressions, there isn't a general way to negate a given expression. With PCRE's you have the advantage of negative look-aheads, which significantly simplify the process of constructing a negated search, at the expense of performance.

^([^/]*\.(?!html$|php$)[^./]*)|[^/.]$
Eclipse
  • 44,851
  • 20
  • 112
  • 171
3

Use this regex -

(.*\.php$)|(.*\.html$)|(.*\/.*)
Gopi
  • 10,073
  • 4
  • 31
  • 45
  • Thank you for answering, but it misses the NOT part. It matches "foo.php" "fo/o" and "foo.html" . It should match all but that. – johnjohn Jul 27 '10 at 17:00