7
preg_match('/te**ed/i', 'tested', $matches);

gives me the following error:

ERROR: nothing to repeat at offset 3

What do I do to allow the pattern to actually contain *?

Tim Pietzcker
  • 328,213
  • 58
  • 503
  • 561
sniper
  • 2,905
  • 6
  • 21
  • 27

4 Answers4

9

To use literal asterisks you have to escape them with backslashes. To match the literal te**ed you would use an expression like this:

preg_match('/te\*\*ed/i', 'tested', $matches); // no match (te**ed != tested)

But I doubt this is what you wanted. If you mean, match any character, you need to use .:

preg_match('/te..ed/is', 'tested', $matches); // match

If you really want any two lower case letter, then this expression:

preg_match('/te[a-z]{2}ed/i', 'tested', $matches); // match
Mark Elliot
  • 75,278
  • 22
  • 140
  • 160
  • I meant using the literal "te**ed". So I assume escaping it is gonna solve the issue :) – sniper Jul 07 '11 at 02:17
  • @sniper: fair enough, but recognize that `$matches` in the expression given will still be empty, whereas `preg_match('/te\*\*ed/i', 'te**ed', $matches)` would produce a non-empty result. – Mark Elliot Jul 07 '11 at 02:18
  • ahh... thats exactly what I need!! :) Is there anyway to quickly escape "te**ed" in php? Any built in function? – sniper Jul 07 '11 at 02:20
  • @sniper: You can use [`preg_quote`](http://php.net/preg_quote) to escape all regex characters. – Mark Elliot Jul 07 '11 at 02:23
  • Great! That solved it! The final regular expression I used : preg_match("/".preg_quote($search_string)."/i",$topic) – sniper Jul 07 '11 at 02:30
  • `If you really want any two lower case letter` ...nope, you are using a case insensitive flag. – mickmackusa May 29 '21 at 05:13
1

If you want to use asterisk-like search, you can use next function:

function match_string($pattern, $str)
{
  $pattern = preg_replace('/([^*])/e', 'preg_quote("$1", "/")', $pattern);
  $pattern = str_replace('*', '.*', $pattern);
  return (bool) preg_match('/^' . $pattern . '$/i', $str);
}

Example:

match_string("*world*","hello world") // returns true
match_string("world*","hello world") // returns false
match_string("*world","hello world") // returns true
match_string("world*","hello world") // returns false
match_string("*ello*w*","hello world") // returns true
match_string("*w*o*r*l*d*","hello world") // returns true
Viktor Kruglikov
  • 519
  • 6
  • 16
1

Improving upon Viktor Kruglikov's answer, this is the PHP 7.3 way of doing such a thing:

private function match(string $pattern, string $target): bool
{
    $pattern = preg_replace_callback('/([^*])/', function($m) {return preg_quote($m[0], '/');}, $pattern);
    $pattern = str_replace('*', '.*', $pattern);
    return (bool) preg_match('/^' . $pattern . '$/i', $target);
}
Riki137
  • 2,076
  • 2
  • 23
  • 26
1

Putting a backslash before any character wil tell PHP that the character should be taken as is, not as a special regex character. So:

preg_match('/te\\**ed/i', 'tested', $matches);
Martin Larente
  • 510
  • 2
  • 9