frosty frosty - 3 months ago 22
PHP Question

Match, not having a word right before a certain word

I would like to match the word 'mice' without any words right before it, but my regex isn't working. What am I doing wrong?

<?php

$string1 = "one mice";
$string2 = "one .mice";
$string3 = "mice";

if (preg_match("~(?<![a-z]+ )\bmice~", $string1)) { echo "1"; }
if (preg_match("~(?<![a-z]+ )\bmice~", $string2)) { echo "2"; }
if (preg_match("~(?<![a-z]+ )\bmice~", $string3)) { echo "3"; }

?>


Expected Result:

23

Actual Result:

null

I expect it echo 2 because instead of having a word before 'mice', it's a period instead. And I expect it to echo 3 because there's no word before the word 'mice'. What am I doing wrong?

Answer Source

You can use negative lookbehind and make the dot optional, i.e.:

if (preg_match('/(?<![a-z] )\.?\bmice\b/i', $subject)) {
    # Successful match
}

Regex explanation:

(?<![a-z] )\.?\bmice\b

Options: Case insensitive

Assert that it is impossible to match the regex below with the match ending at this position (negative lookbehind) «(?<![a-z] )»
   Match a single character in the range between “a” and “z” (case insensitive) «[a-z]»
   Match the character “ ” literally « »
Match the character “.” literally «\.?»
   Between zero and one times, as many times as possible, giving back as needed (greedy) «?»
Assert position at a word boundary (position preceded or followed—but not both—by a Unicode letter, digit, or underscore) «\b»
Match the character string “mice” literally (case insensitive) «mice»
Assert position at a word boundary (position preceded or followed—but not both—by a Unicode letter, digit, or underscore) «\b»

Regex101 Demo


Ideone Demo


Note:

  1. PHP preg >= 5.6.11 does not support infinite repetition inside lookbehind (?<![a-z]+ )