39

I want to give the possibility to match string with wildcard *.

Example

$mystring = 'dir/folder1/file';
$pattern = 'dir/*/file';

stringMatchWithWildcard($mystring,$pattern);  //> Returns true

Example 2:

$mystring = 'string bl#abla;y';
$pattern = 'string*y'; 

stringMatchWithWildcard($mystring,$pattern);  //> Returns true

I thought something like:

function stringMatch($source,$pattern) {
    $pattern = preg_quote($pattern,'/');        
    $pattern = str_replace( '\*' , '.*?', $pattern);   //> This is the important replace
    return (bool)preg_match( '/^' . $pattern . '$/i' , $source );
}

Basically replacing * to .*? (considering in *nix environment * matches empty string) ©vbence

Any improvments/suggests?

// Added return (bool) because preg_match returns int

dynamic
  • 46,985
  • 55
  • 154
  • 231

6 Answers6

61

There is no need for preg_match here. PHP has a wildcard comparison function, specifically made for such cases:

fnmatch()

And fnmatch('dir/*/file', 'dir/folder1/file') would likely already work for you. But beware that the * wildcard would likewise add further slashes, like preg_match would.

mario
  • 144,265
  • 20
  • 237
  • 291
  • hi mario. fnmatches has some other feature like `[]`. I just need `*` as "special char" – dynamic May 29 '11 at 16:11
  • 5
    fnmatch is not supported on non-POSIX systems. (I see that php5.3+ also supports windows now). So this is not always the best way – Pinoniq May 21 '14 at 14:49
4

You should just use .* instead.

$pattern = str_replace( '*' , '.*', $pattern);   //> This is the important replace

Edit: Also your ^ and $ were in the wrong order.

<?php

function stringMatchWithWildcard($source,$pattern) {
    $pattern = preg_quote($pattern,'/');        
    $pattern = str_replace( '\*' , '.*', $pattern);   
    return preg_match( '/^' . $pattern . '$/i' , $source );
}

$mystring = 'dir/folder1/file';
$pattern = 'dir/*/file';

echo stringMatchWithWildcard($mystring,$pattern); 



$mystring = 'string bl#abla;y';
$pattern = 'string*y'; 

echo stringMatchWithWildcard($mystring,$pattern); 

Working demo: http://www.ideone.com/mGqp2

Dogbert
  • 212,659
  • 41
  • 396
  • 397
  • I don't know if I want to give the possibility to match this `'dir//file'` with `'dir/*/file'` – dynamic May 28 '11 at 17:08
  • `.*` is greedy, it will eat all the rest of your string, no just the minimal number of characters to continue with the patters. So if you have anything after `.*` the result will be always false. – vbence May 28 '11 at 17:09
  • I thought that was exactly what you wanted to do with `.+?` from your description. – Dogbert May 28 '11 at 17:10
  • @vbence `preg_match('/.*a/', 'aa')` ? – Dogbert May 28 '11 at 17:13
  • Ok it seems `match` will give the same results. – vbence May 28 '11 at 17:32
  • @vbence maybe in this case it's the same with or without `?` because 1) there aren't any () capturing parts 2) it's defined with `^ $` – dynamic May 28 '11 at 17:37
2
.+?

Causes non-greedy matching for all characters. This is NOT equal to "*" becuase it will not match the empty string.

The following pattern will match the empty string too:

.*?

so...

stringMatchWithWildcard ("hello", "hel*lo"); // will give true
vbence
  • 20,084
  • 9
  • 69
  • 118
  • do you think I should allow for empty string? Consider dir too: `'dir//file'` matching `'dir/*/file'` ? – dynamic May 28 '11 at 17:11
  • 2
    If you want it to work analogous to how OS shells work, then you have to allow for the empty string. Just try `echo > hello` followed by `dir hello*` in windows or `ls hello*` in *nix. In this context * matches the empty string. – vbence May 28 '11 at 17:14
  • It would be polite to give a comment with your -1. – vbence May 28 '11 at 17:16
  • ah nice! thanks for the *nix comparsion! (also i didnt -1 your answer, no reason for me to do that) – dynamic May 28 '11 at 17:17
  • @yes123 Yep, I know, not accusing. :) – vbence May 28 '11 at 17:20
  • I would like to hear the downvote reason here because acutally i am using this lol – dynamic May 28 '11 at 17:51
  • @dynamic Obviously it worked.... and i really dislike uncommented downvotes... random people picking up points. So... Upvote – james walker Dec 29 '16 at 17:10
2

You're mixing up ending ($) and beginning (^). This:

preg_match( '/$' . $pattern . '^/i' , $source );

Should be:

preg_match( '/^' . $pattern . '$/i' , $source );
netcoder
  • 66,435
  • 19
  • 125
  • 142
0
$pattern = str_replace( '\*' , '.+?', $pattern);   // at least one character
Tim13
  • 26
  • 3
  • Please add some explanation to your code - have a look at the other answers to this question for some inspiration – Nico Haase Feb 25 '19 at 09:18
0

The one problem you'll have is that the call to preg_quote() will escape the asterisk character. Given that, your str_replace() will replace the *, but not the escape character in front of it.

Therefore you should change the str_replace('*' ..) with str_replace('\*'..)

Spudley
  • 166,037
  • 39
  • 233
  • 307