8

Is there a way to put a wildcard in a string? The reason why I am asking is because currently I have a function to search for a substring between two substrings (i.e grab the contents between "my" and "has fleas" in the sentence "my dog has fleas", resulting in "dog").

function get_string_between($string, $start, $end){ 
    $string = " ".$string; 
    $ini = strpos($string,$start); 
    if ($ini == 0) return ""; 
    $ini += strlen($start); 
    $len = strpos($string,$end,$ini) - $ini; 
    return substr($string,$ini,$len); 
} 

What I want to do is have it search with a wildcard in the string. So say I search between "%WILDCARD%" and "has fleas" in the sentence "My dog has fleas" - it would still output "dog".

I don't know if I explained it too well but hopefully someone will understand me :P. Thank you very much for reading!

1
  • 1
    if you want wildcards, you can use regular expressions instead. Commented Feb 21, 2010 at 8:57

5 Answers 5

11

This is one of the few cases where regular expressions are actually helpful. :)

if (preg_match('/my (\w+) has/', $str, $matches)) {
    echo $matches[1];
}

See the documentation for preg_match.

Sign up to request clarification or add additional context in comments.

5 Comments

That's just ignorant, regular expressions are excellent tools.
@Raveren: Regular expressions are terrible tools in the hand of fools. Way to many people use them without understanding their limitations, what kind of engines exist, etc.
Regular expressions are terrible tools in the hand of fools. So is literally every other tool in existence.
I don't know of any other (programmer) tool that is so often misused.
@LukášLalinský can you blame us? The syntax for regular expressions is pretty ugly. There is literally not one time I use a reg ex without Googling it
8

wildcard pattern could be converted to regex pattern like this

function wildcard_match($pattern, $subject) {
  $pattern = strtr($pattern, array(
    '*' => '.*?', // 0 or more (lazy) - asterisk (*)
    '?' => '.', // 1 character - question mark (?)
  ));
  return preg_match("/$pattern/", $subject);
}

if string contents special characters, e.g. \.+*?^$|{}/'#, they should be \-escaped

don't tested:

function wildcard_match($pattern, $subject) {
  // quotemeta function has most similar behavior,
  // it escapes \.+*?^$[](), but doesn't escape |{}/'#
  // we don't include * and ?
  $special_chars = "\.+^$[]()|{}/'#";
  $special_chars = str_split($special_chars);
  $escape = array();
  foreach ($special_chars as $char) $escape[$char] = "\\$char";
  $pattern = strtr($pattern, $escape);
  $pattern = strtr($pattern, array(
    '*' => '.*?', // 0 or more (lazy) - asterisk (*)
    '?' => '.', // 1 character - question mark (?)
  ));
  return preg_match("/$pattern/", $subject);
}

1 Comment

There should be possible a preg_quote arround at the $pattern
4

Use a regex.

$string = "My dog has fleas";
if (preg_match("/\S+ (\S+) has fleas/", $string, $matches))
  echo ($matches[1]);
else
  echo ("Not found");

\S means any non-space character, + means one or more of the previous thing, so \S+ means match one or more non-space characters. (…) means capture the content of the submatch and put into the $matches array.

Comments

4

I agree that regex are much more flexible than wildcards, but sometimes all you want is a simple way to define patterns. For people looking for a portable solution (not *NIX only) here is my implementation of the function:

function wild_compare($wild, $string) {
    $wild_i = 0;
    $string_i = 0;

    $wild_len = strlen($wild);
    $string_len = strlen($string);

    while ($string_i < $string_len && $wild[$wild_i] != '*') {
        if (($wild[$wild_i] != $string[$string_i]) && ($wild[$wild_i] != '?')) {
            return 0;
        }
        $wild_i++;
        $string_i++;
    }

    $mp = 0;
    $cp = 0;

    while ($string_i < $string_len) {
        if ($wild[$wild_i] == '*') {
            if (++$wild_i == $wild_len) {
                return 1;
            }
            $mp = $wild_i;
            $cp = $string_i + 1;
        }
        else
        if (($wild[$wild_i] == $string[$string_i]) || ($wild[$wild_i] == '?')) {
            $wild_i++;
            $string_i++;
        }
        else {
            $wild_i = $mp;
            $string_i = $cp++;
        }
    }

    while ($wild[$wild_i] == '*') {
        $wild_i++;
    }

    return $wild_i == $wild_len ? 1 : 0;
}

Naturally the PHP implementation is slower than fnmatch(), but it would work on any platform.

It can be used like this:

if (wild_compare('regex are * useful', 'regex are always useful') == 1) {
    echo "I'm glad we agree on this";
}

1 Comment

nice! we had a requirement to allow our staff to enter regular expression rules to match up certain pieces of data. As they don't understand regex, this was the perfect solution!
3

If you insist to use a wildcard (and yes, PREG is much better) you can use the function fnmatch.

ex:

if (fnmatch('my * has', $str)) { }

3 Comments

For now, this function is not available on non-POSIX compliant systems except Windows. So it works on Windows, now.
@Moradnejad that is true, I'll edit my message so it might help someone else!
LOL. I didn't expect you this fast on a 10-year-old answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.