Wildcard Pattern Matching

19 Jun, 2022
Given a text and a wildcard pattern, implement wildcard pattern matching algorithm that finds if wildcard pattern is matched with text. The matching should cover the entire text (not partial text). The wildcard pattern can include the characters ‘?’ and ‘*’ 
‘?’ – matches any single character 
‘*’ – Matches any sequence of characters (including the empty sequence)
For example:
Text = "baaabab",
Pattern = “*****ba*****ab", output : true
Pattern = "baaa?ab", output : true
Pattern = "ba*a?", output : true
Pattern = "a*ab", output : false 
Each occurrence of ‘?’ character in wildcard pattern can be replaced with any other character and each occurrence of ‘*’ with a sequence of characters such that the wildcard pattern becomes identical to the input string after replacement.
Let’s consider any character in the pattern.
Chapters
descriptions off, selected
captions settings, opens captions settings dialog
captions off, selected
English
This is a modal window.
Beginning of dialog window. Escape will cancel and close the window.
End of dialog window.
Case 1: The character is ‘*’ . Here two cases arises as follows:  
We can ignore ‘*’ character and move to next character in the Pattern.‘*’ character matches with one or more characters in Text. Here we will move to next character in the string.
We can ignore ‘*’ character and move to next character in the Pattern.
‘*’ character matches with one or more characters in Text. Here we will move to next character in the string.
Case 2: The character is ‘?’ We can ignore current character in Text and move to next character in the Pattern and Text.
Case 3: The character is not a wildcard character If current character in Text matches with current character in Pattern, we move to next character in the Pattern and Text. If they do not match, wildcard pattern and Text do not match.We can use Dynamic Programming to solve this problem:
Let T[i][j] is true if first i characters in given string matches the first j characters of pattern. 
DP Initialization: 
// both text and pattern are null
T[0][0] = true; 

// pattern is null
T[i][0] = false; 

// text is null
T[0][j] = T[0][j - 1] if pattern[j – 1] is '*'  
DP relation: 
// If current characters match, result is same as 
// result for lengths minus one. Characters match
// in two cases:
// a) If pattern character is '?' then it matches  
//    with any character of text. 
// b) If current characters in both match
if ( pattern[j – 1] == ‘?’) || 
     (pattern[j – 1] == text[i - 1])
    T[i][j] = T[i-1][j-1]   
 
// If we encounter ‘*’, two choices are possible-
// a) We ignore ‘*’ character and move to next 
//    character in the pattern, i.e., ‘*’ 
//    indicates an empty sequence.
// b) '*' character matches with ith character in
//     input 
else if (pattern[j – 1] == ‘*’)
    T[i][j] = T[i][j-1] || T[i-1][j]  

else // if (pattern[j – 1] != text[i - 1])
    T[i][j]  = false 
Implementation:
Below is the implementation of the above dynamic programming approach.
C++
Java
Python3
C#
Javascript
// C++ program to implement wildcard// pattern matching algorithm#include <bits/stdc++.h>using namespace std; // Function that matches input str with// given wildcard patternbool strmatch(char str[], char pattern[], int n, int m){    // empty pattern can only match with    // empty string    if (m == 0)        return (n == 0);     // lookup table for storing results of    // subproblems    bool lookup[n + 1][m + 1];     // initialize lookup table to false    memset(lookup, false, sizeof(lookup));     // empty pattern can match with empty string    lookup[0][0] = true;     // Only '*' can match with empty string    for (int j = 1; j <= m; j++)        if (pattern[j - 1] == '*')            lookup[0][j] = lookup[0][j - 1];     // fill the table in bottom-up fashion    for (int i = 1; i <= n; i++) {        for (int j = 1; j <= m; j++) {            // Two cases if we see a '*'            // a) We ignore ‘*’ character and move            //    to next  character in the pattern,            //     i.e., ‘*’ indicates an empty sequence.            // b) '*' character matches with ith            //     character in input            if (pattern[j - 1] == '*')                lookup[i][j]                    = lookup[i][j - 1] || lookup[i - 1][j];             // Current characters are considered as            // matching in two cases            // (a) current character of pattern is '?'            // (b) characters actually match            else if (pattern[j - 1] == '?'                     || str[i - 1] == pattern[j - 1])                lookup[i][j] = lookup[i - 1][j - 1];             // If characters don't match            else                lookup[i][j] = false;        }    }     return lookup[n][m];} int main(){    char str[] = "baaabab";    char pattern[] = "*****ba*****ab";    // char pattern[] = "ba*****ab";    // char pattern[] = "ba*ab";    // char pattern[] = "a*ab";    // char pattern[] = "a*****ab";    // char pattern[] = "*a*****ab";    // char pattern[] = "ba*ab****";    // char pattern[] = "****";    // char pattern[] = "*";    // char pattern[] = "aa?ab";    // char pattern[] = "b*b";    // char pattern[] = "a*a";    // char pattern[] = "baaabab";    // char pattern[] = "?baaabab";    // char pattern[] = "*baaaba*";     if (strmatch(str, pattern, strlen(str),                 strlen(pattern)))        cout << "Yes" << endl;    else        cout << "No" << endl;     return 0;}
// Java program to implement wildcard// pattern matching algorithmimport java.util.Arrays;public class GFG {     // Function that matches input str with    // given wildcard pattern    static boolean strmatch(String str, String pattern,                            int n, int m)    {        // empty pattern can only match with        // empty string        if (m == 0)            return (n == 0);         // lookup table for storing results of        // subproblems        boolean[][] lookup = new boolean[n + 1][m + 1];         // initialize lookup table to false        for (int i = 0; i < n + 1; i++)            Arrays.fill(lookup[i], false);         // empty pattern can match with empty string        lookup[0][0] = true;         // Only '*' can match with empty string        for (int j = 1; j <= m; j++)            if (pattern.charAt(j - 1) == '*')                lookup[0][j] = lookup[0][j - 1];         // fill the table in bottom-up fashion        for (int i = 1; i <= n; i++)        {            for (int j = 1; j <= m; j++)            {                // Two cases if we see a '*'                // a) We ignore '*'' character and move                //    to next  character in the pattern,                //     i.e., '*' indicates an empty                //     sequence.                // b) '*' character matches with ith                //     character in input                if (pattern.charAt(j - 1) == '*')                    lookup[i][j] = lookup[i][j - 1]                                   || lookup[i - 1][j];                 // Current characters are considered as                // matching in two cases                // (a) current character of pattern is '?'                // (b) characters actually match                else if (pattern.charAt(j - 1) == '?'                         || str.charAt(i - 1)                                == pattern.charAt(j - 1))                    lookup[i][j] = lookup[i - 1][j - 1];                 // If characters don't match                else                    lookup[i][j] = false;            }        }         return lookup[n][m];    }        // Driver code    public static void main(String args[])    {        String str = "baaabab";        String pattern = "*****ba*****ab";        // String pattern = "ba*****ab";        // String pattern = "ba*ab";        // String pattern = "a*ab";        // String pattern = "a*****ab";        // String pattern = "*a*****ab";        // String pattern = "ba*ab****";        // String pattern = "****";        // String pattern = "*";        // String pattern = "aa?ab";        // String pattern = "b*b";        // String pattern = "a*a";        // String pattern = "baaabab";        // String pattern = "?baaabab";        // String pattern = "*baaaba*";         if (strmatch(str, pattern, str.length(),                     pattern.length()))            System.out.println("Yes");        else            System.out.println("No");    }}// This code is contributed by Sumit Ghosh
# Python program to implement wildcard# pattern matching algorithm # Function that matches input strr with# given wildcard pattern  def strrmatch(strr, pattern, n, m):     # empty pattern can only match with    # empty string    if (m == 0):        return (n == 0)     # lookup table for storing results of    # subproblems    lookup = [[False for i in range(m + 1)] for j in range(n + 1)]     # empty pattern can match with empty string    lookup[0][0] = True     # Only '*' can match with empty string    for j in range(1, m + 1):        if (pattern[j - 1] == '*'):            lookup[0][j] = lookup[0][j - 1]     # fill the table in bottom-up fashion    for i in range(1, n + 1):        for j in range(1, m + 1):             # Two cases if we see a '*'            # a) We ignore ‘*’ character and move            # to next character in the pattern,            # i.e., ‘*’ indicates an empty sequence.            # b) '*' character matches with ith            # character in input            if (pattern[j - 1] == '*'):                lookup[i][j] = lookup[i][j - 1] or lookup[i - 1][j]             # Current characters are considered as            # matching in two cases            # (a) current character of pattern is '?'            # (b) characters actually match            else if (pattern[j - 1] == '?' or strr[i - 1] == pattern[j - 1]):                lookup[i][j] = lookup[i - 1][j - 1]             # If characters don't match            else:                lookup[i][j] = False     return lookup[n][m] # Driver code  strr = "baaabab"pattern = "*****ba*****ab"# char pattern[] = "ba*****ab"# char pattern[] = "ba*ab"# char pattern[] = "a*ab"# char pattern[] = "a*****ab"# char pattern[] = "*a*****ab"# char pattern[] = "ba*ab****"# char pattern[] = "****"# char pattern[] = "*"# char pattern[] = "aa?ab"# char pattern[] = "b*b"# char pattern[] = "a*a"# char pattern[] = "baaabab"# char pattern[] = "?baaabab"# char pattern[] = "*baaaba*" if (strrmatch(strr, pattern, len(strr), len(pattern))):    print("Yes")else:    print("No") # This code is contributed by shubhamsingh10
// C# program to implement wildcard// pattern matching algorithmusing System; class GFG {     // Function that matches input str with    // given wildcard pattern    static Boolean strmatch(String str,                            String pattern,                            int n, int m)    {        // empty pattern can only match with        // empty string        if (m == 0)            return (n == 0);         // lookup table for storing results of        // subproblems        Boolean[, ] lookup = new Boolean[n + 1, m + 1];         // initialize lookup table to false        for (int i = 0; i < n + 1; i++)            for (int j = 0; j < m + 1; j++)                lookup[i, j] = false;         // empty pattern can match with        // empty string        lookup[0, 0] = true;         // Only '*' can match with empty string        for (int j = 1; j <= m; j++)            if (pattern[j - 1] == '*')                lookup[0, j] = lookup[0, j - 1];         // fill the table in bottom-up fashion        for (int i = 1; i <= n; i++) {            for (int j = 1; j <= m; j++) {                // Two cases if we see a '*'                // a) We ignore '*'' character and move                // to next character in the pattern,                //     i.e., '*' indicates an empty                //     sequence.                // b) '*' character matches with ith                //     character in input                if (pattern[j - 1] == '*')                    lookup[i, j] = lookup[i, j - 1]                                   || lookup[i - 1, j];                 // Current characters are considered as                // matching in two cases                // (a) current character of pattern is '?'                // (b) characters actually match                else if (pattern[j - 1] == '?'                         || str[i - 1] == pattern[j - 1])                    lookup[i, j] = lookup[i - 1, j - 1];                 // If characters don't match                else                    lookup[i, j] = false;            }        }        return lookup[n, m];    }     // Driver Code    public static void Main(String[] args)    {        String str = "baaabab";        String pattern = "*****ba*****ab";        // String pattern = "ba*****ab";        // String pattern = "ba*ab";        // String pattern = "a*ab";        // String pattern = "a*****ab";        // String pattern = "*a*****ab";        // String pattern = "ba*ab****";        // String pattern = "****";        // String pattern = "*";        // String pattern = "aa?ab";        // String pattern = "b*b";        // String pattern = "a*a";        // String pattern = "baaabab";        // String pattern = "?baaabab";        // String pattern = "*baaaba*";         if (strmatch(str, pattern, str.Length,                     pattern.Length))            Console.WriteLine("Yes");        else            Console.WriteLine("No");    }} // This code is contributed by Rajput-Ji
<script> // JavaScript program to implement wildcard// pattern matching algorithm  // Function that matches input str with// given wildcard patternfunction strmatch(str, pattern, n, m){    // empty pattern can only match with    // empty string    if (m == 0)        return (n == 0);     // lookup table for storing results of    // subproblems    // initialize lookup table to false    let lookup = new Array(n + 1).fill(false).map(()=>new Array(m + 1).fill(false));     // empty pattern can match with empty string    lookup[0][0] = true;     // Only '*' can match with empty string    for (let j = 1; j <= m; j++)        if (pattern[j - 1] == '*')            lookup[0][j] = lookup[0][j - 1];     // fill the table in bottom-up fashion    for (let i = 1; i <= n; i++) {        for (let j = 1; j <= m; j++) {            // Two cases if we see a '*'            // a) We ignore ‘*’ character and move            //    to next  character in the pattern,            //     i.e., ‘*’ indicates an empty sequence.            // b) '*' character matches with ith            //     character in input            if (pattern[j - 1] == '*')                lookup[i][j]                    = lookup[i][j - 1] || lookup[i - 1][j];             // Current characters are considered as            // matching in two cases            // (a) current character of pattern is '?'            // (b) characters actually match            else if (pattern[j - 1] == '?'                     || str[i - 1] == pattern[j - 1])                lookup[i][j] = lookup[i - 1][j - 1];             // If characters don't match            else                lookup[i][j] = false;        }    }     return lookup[n][m];} // driver code let str = "baaabab";let pattern = "*****ba*****ab";// let pattern = "ba*****ab";// let pattern = "ba*ab";// let pattern = "a*ab";// let pattern = "a*****ab";// let pattern = "*a*****ab";// let pattern = "ba*ab****";// let pattern = "****";// let pattern = "*";// let pattern = "aa?ab";// let pattern = "b*b";// let pattern = "a*a";// let pattern = "baaabab";// let pattern = "?baaabab";// let pattern = "*baaaba*"; if (strmatch(str, pattern, str.length,pattern.length))    document.write("Yes","</br>")else    document.write("No","</br>")   // This code is contributed by shinjanpatra </script>
Yes
Time complexity: O(m x n) 
Auxiliary space: O(m x n)
C++
Javascript
// C++ program to implement wildcard// pattern matching algorithm #include <bits/stdc++.h> using namespace std; // Function that matches input str with// given wildcard patternvector<vector<int> > dp;int finding(string& s, string& p, int n, int m){    // return 1 if n and m are negative    if (n < 0 && m < 0)        return 1;       // return 0 if m is negative    if (m < 0)        return 0;       // return n if n is negative    if (n < 0)    {        // while m is positive        while (m >= 0)        {            if (p[m] != '*')                return 0;            m--;        }        return 1;    }        // if dp state is not visited    if (dp[n][m] == -1)    {        if (p[m] == '*')        {            return dp[n][m] = finding(s, p, n - 1, m)                              || finding(s, p, n, m - 1);        }        else        {            if (p[m] != s[n] && p[m] != '?')                return dp[n][m] = 0;            else                return dp[n][m]                       = finding(s, p, n - 1, m - 1);        }    }       // return dp[n][m] if dp state is previsited    return dp[n][m];}  bool isMatch(string s, string p){    dp.clear();         // resize the dp array    dp.resize(s.size() + 1, vector<int>(p.size() + 1, -1));    return dp[s.size()][p.size()]           = finding(s, p, s.size() - 1, p.size() - 1);} // Driver codeint main(){    string str = "baaabab";    string pattern = "*****ba*****ab";    // char pattern[] = "ba*****ab";    // char pattern[] = "ba*ab";    // char pattern[] = "a*ab";    // char pattern[] = "a*****ab";    // char pattern[] = "*a*****ab";    // char pattern[] = "ba*ab****";    // char pattern[] = "****";    // char pattern[] = "*";    // char pattern[] = "aa?ab";    // char pattern[] = "b*b";    // char pattern[] = "a*a";    // char pattern[] = "baaabab";    // char pattern[] = "?baaabab";    // char pattern[] = "*baaaba*";     if (isMatch(str, pattern))        cout << "Yes" << endl;    else        cout << "No" << endl;     return 0;}
<script> // JavaScript program to implement wildcard// pattern matching algorithm // Function that matches input str with// given wildcard patternlet dp = [];function finding(s, p, n, m){    // return 1 if n and m are negative    if (n < 0 && m < 0)        return 1;       // return 0 if m is negative    if (m < 0)        return 0;       // return n if n is negative    if (n < 0)    {        // while m is positive        while (m >= 0)        {            if (p[m] != '*')                return 0;            m--;        }        return 1;    }        // if dp state is not visited    if (dp[n][m] == -1)    {        if (p[m] == '*')        {            return dp[n][m] = finding(s, p, n - 1, m)                              || finding(s, p, n, m - 1);        }        else        {            if (p[m] != s[n] && p[m] != '?')                return dp[n][m] = 0;            else                return dp[n][m]                       = finding(s, p, n - 1, m - 1);        }    }       // return dp[n][m] if dp state is previsited    return dp[n][m];}  function isMatch(s, p){    dp = [];         // resize the dp array    dp = new Array(s.length+1).fill(1).map(()=>new Array(p.length+1).fill(-1));    return dp[s.length][p.length]           = finding(s, p, s.length - 1, p.length - 1);} // Driver code let str = "baaabab";let pattern = "*****ba*****ab";// char pattern[] = "ba*****ab";// char pattern[] = "ba*ab";// char pattern[] = "a*ab";// char pattern[] = "a*****ab";// char pattern[] = "*a*****ab";// char pattern[] = "ba*ab****";// char pattern[] = "****";// char pattern[] = "*";// char pattern[] = "aa?ab";// char pattern[] = "b*b";// char pattern[] = "a*a";// char pattern[] = "baaabab";// char pattern[] = "?baaabab";// char pattern[] = "*baaaba*"; if (isMatch(str, pattern))    console.log("Yes")else    console.log("No") // This code is contributed by shinjanpatra </script>
Yes
Time complexity: O(m x n). 
Auxiliary space:  O(m x n). 
Further Scope: We can improve space complexity by making use of the fact that we only uses the result from last row. 
C++
// C++ program to implement wildcard// pattern matching algorithm#include <bits/stdc++.h>using namespace std; // Function that matches input str with// given wildcard patternbool strmatch(char str[], char pattern[], int m, int n){    // lookup table for storing results of    // subproblems    vector<bool> prev(m + 1, false), curr(m + 1, false);     // empty pattern can match with empty string    prev[0] = true;     // fill the table in bottom-up fashion    for (int i = 1; i <= n; i++) {         bool flag = true;        for (int ii = 1; ii < i; ii++) {            if (pattern[ii - 1] != '*') {                flag = false;                break;            }        }        curr[0] = flag; // for every row we are assigning                        // 0th column value.        for (int j = 1; j <= m; j++) {            // Two cases if we see a '*'            // a) We ignore ‘*’ character and move            //    to next  character in the pattern,            //     i.e., ‘*’ indicates an empty sequence.            // b) '*' character matches with ith            //     character in input            if (pattern[i - 1] == '*')                curr[j] = curr[j - 1] || prev[j];             // Current characters are considered as            // matching in two cases            // (a) current character of pattern is '?'            // (b) characters actually match            else if (pattern[i - 1] == '?'                     || str[j - 1] == pattern[i - 1])                curr[j] = prev[j - 1];             // If characters don't match            else                curr[j] = false;        }        prev = curr;    }     return prev[m];} int main(){    char str[] = "baaabab";    char pattern[] = "*****ba*****ab";    // char pattern[] = "ba*****ab";    // char pattern[] = "ba*ab";    // char pattern[] = "a*ab";    // char pattern[] = "a*****ab";    // char pattern[] = "*a*****ab";    // char pattern[] = "ba*ab****";    // char pattern[] = "****";    // char pattern[] = "*";    // char pattern[] = "aa?ab";    // char pattern[] = "b*b";    // char pattern[] = "a*a";    // char pattern[] = "baaabab";    // char pattern[] = "?baaabab";    // char pattern[] = "*baaaba*";     if (strmatch(str, pattern, strlen(str),                 strlen(pattern)))        cout << "Yes" << endl;    else        cout << "No" << endl;     return 0;}
Yes
Time complexity: O(m x n).
Auxiliary space:  O(m). 
One more improvement is you can merge consecutive ‘*’ in the pattern to single ‘*’ as they mean the same thing. For example for pattern “*****ba*****ab”, if we merge consecutive stars, the resultant string will be “*ba*ab”. So, value of m is reduced from 14 to 6.
This article is contributed by Aditya Goel. If you like GeeksforGeeks and would like to contribute, you can also write an article and mail your article to review-team@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.
Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above. 
Rajput-Ji
SHUBHAMSINGH10
yogeshkumar20
shivam2608
saurabh1990aror
singghakshay
gabaa406
kapoorsagar226
rs1686740
simmytarika5
avanigajaria
sanskar84
shinjanpatra
Amazon
InMobi
Microsoft
Ola Cabs
United Health Group
Walmart
Zoho
Dynamic Programming
Pattern Searching
Strings
Zoho
Amazon
Microsoft
Ola Cabs
Walmart
InMobi
United Health Group
Strings
Dynamic Programming
Pattern Searching
Writing code in comment?
Please use ide.geeksforgeeks.org,
generate link and share the link here.