[ACCEPTED]-PHP Reverse Preg_match-reverse

Accepted answer
Score: 11

This can be done if you definitely want 5 to use a "negative regex" instead of simply 4 inverting the result of the positive regex:

if(preg_match("/^(?:(?!" . $filter . ").)*$/i", $node)) {
    echo $node;

will 3 match a string if it doesn't contain the 2 regex/substring in $filter.

Explanation: (taking office as our example 1 string)

^          # Anchor the match at the start of the string
(?:        # Try to match the following:
 (?!       # (unless it's possible to match
  office   # the text "office" at this point)
 )         # (end of negative lookahead),
 .         # Any character
)*         # zero or more times
$          # until the end of the string
Score: 7

The (?!...) negative assertion is what you're looking for.

To exclude 6 a certain string from appearing anywhere 5 in the subject you can use this double assertion 4 method:

preg_match('/(?=^((?!not_this).)+$)  (......)/xs', $string);

It allows to specify an arbitrary 3 (......) main regex still. But you could 2 just leave that out, if you only want to 1 forbid a string.

Score: 0

Answer number 2 by mario is the correct 80 answer, and here is why:

First to answer 79 the comment by Justin Morgan,

I'm curious, do 78 you have any idea what the performance of 77 this would be as opposed to the !preg_match() approach? I'm 76 not in a place where I can test them both. – Justin 75 Morgan Apr 19 '11 at 21:53

Consider the gate 74 logic for a moment.

When to negate preg_match(): when 73 looking for a match and you want the condition 72 to be 1)true for the absence of the desired 71 regex, or 2)false for the regex being present.

When 70 to use negative assertion on the regex: when 69 looking for a match and you want the condition 68 to be true if the string ONLY matches the 67 regex, and fail if anything else is found. This 66 is necessary if you really need to test 65 for undesireable characters while allowing 64 ommission of permitted characters.

Negating 63 the result of (preg_match() === 1) only 62 tests if the regex is present. If 'bar' is 61 required, and numbers aren't allowed, the 60 following won't work:

if (preg_match('bar', 'foo2bar') === 1) {
  echo "found 'bar'"; // but a number is here, so fail.

if (!pregmatch('[0-9]', 'foobar') === 1) {
  echo "no numbers found"; // but didn't test for 'bar', so fail.

So, in order to really 59 test multiple regexes, a beginner would 58 test using multiple preg_match() calls... we 57 know this is a very amateur way to do it.

So, the 56 Op wants to test a string for possible regexes, but 55 the conditional may only pass as true if 54 the string contains at least one of them. For 53 most simple cases, simply negating preg_match() will 52 suffice, but for more complex or extensive 51 regex patterns, it won't. I will use my 50 situation for a more real-life scenario:

Say 49 you want to have a user form for a person's 48 name, particularly a last name. You want 47 your system to accept all letters regardless 46 of case and placement, accept hyphens, accept 45 apostrophes, and exclude all other characters. We 44 know that matching a regex for all undesired 43 characters is the first thing we think of, but 42 imagine you are supporting UTF-8... that's 41 alot of characters! Your program will be 40 nearly as big as the UTF-8 table just on 39 a single line! I don't care what hardware 38 you have, your server application has a 37 finite limit on how long a command be, not 36 to mention the limit of 200 parenthesized 35 subpatterns, so the ENTIRE UTF-8 character 34 table (minus [A-Z],[a-z],-,and ') is too 33 long, never mind that the program itself 32 will be HUGE!

Since we won't use an if (!preg_match('.#\\$\%... this 31 can be quite long and impossible to evaluate... on 30 a string to see if the string is bad, we 29 should instead test the easier way, with 28 an assertion negative lookaround on the 27 regex, then negate the overall result using:

  $string = "O'Reilly-Finlay";
  if (preg_match('/?![a-z\'-]/i', $string) === 0) {
    echo "the given string matched exclusively for regex pattern";
    // should not work on error, since preg_match returns false, which is not an int (we tested for identity, not equality)
  } else {
    echo "the given string did not match exclusively to the regex pattern";

If 26 we only looked for the regex [a-z\'-]/i 25 , all we say is "match string if it contains 24 ANY of those things", so bad characters 23 aren't tested. If we negated at the function, we 22 say "return false if we find a match that 21 contained any of these things". This isn't 20 right either, so we need to say "return 19 false if we match ANYTHING not in the regex", which 18 is done with lookahead. I know the bells 17 are going off in someone's head, and they 16 are thinking wildcard expansion style... no, lookahead 15 doesn't do this, it just does negation on 14 each match, and continues. So, it checks 13 first character for regex, if it matches, it 12 moves on until it finds a non-match or the 11 end. After it finishes, everything that 10 was found to not match the regex is returned 9 to the match array, or simply returns 1. In 8 short, assert negative on regex 'a' is the 7 opposite of matching regex 'b', where 'b' contains 6 EVERYTHING ELSE not matchable by 'a'. Great 5 for when 'b' would be ungodly extensive.

Note: if 4 my regex has an error in it, I apologize... I 3 have been using Lua for the last few months, so 2 I may be mixing my regex rules. Otherwise, the 1 '?!' is proper lookahead syntax for PHP.

More Related questions