RegEx Matching

Last Updated : 8 Sep, 2026

Given a pattern string pat and a text string txt, check if pattern matches according to the following rules:

  • If pat is preceded by a ^, the pattern is matched against the starting position of txt, excluding the ^.
  • If pat is succeeded by a $, the pattern is matched against the ending position of txt.
  • If neither marker is present, check whether pat is a substring of txt.
  • If both markers are present, then both the starting and ending positions are matched.

Return true if pat matches txt according to the above rules, otherwise return false.

Examples:

Input: pat = "^coal", txt = "coaltar"
Output: true
Explanation: The pattern "coal" is present at the beginning of the string, so the output is true.

Input: pat = "tar$", txt = "coaltar"
Output: true
Explanation: The pattern "tar" (with the $ marker removed) matches the ending position of txt, so the output is true.

Input: pat = "^a$", txt = "aba"
Output: true
Explanation: The pattern "a" (with both ^ and $ markers removed) matches both the starting and ending positions of txt, so the output is true.

Try It Yourself
redirect icon

Using KMP Search - O(|txt| + |pat|) Time and O(|pat|) Space

  • If ^ is present at the beginning, compare it with prefix of txt
  • If $ is present at the end of pat, compare it with suffix of txt
  • If both are not present, use KMP to search.

Illustration:

  • Take pat = "^coal", txt = "coaltar".
  • pat starts with ^ and does not end with $, so only the start-anchored case applies.
  • The core pattern (with ^ removed) is "coal".
  • Checking whether txt starts with "coal": txt = "coaltar", and its first 4 characters are exactly "coal", so this matches.
  • Since the prefix matches, the result is true.
C++
#include <bits/stdc++.h>
using namespace std;

// builds the longest-prefix-suffix array used by 
// KMP to skip redundant comparisons
vector<int> buildLps(string &pat) {
    int n = pat.length();
    vector<int> lps(n, 0);
    int length = 0;
    int i = 1;
    while (i < n) {
        if (pat[i] == pat[length]) {
            length++;
            lps[i] = length;
            i++;
        } else {
            if (length!= 0) {
                length = lps[length - 1];
            } else {
                lps[i] = 0;
                i++;
            }
        }
    }
    return lps;
}

// searches for pat as a substring of txt using KMP,
// avoiding re-scanning matched characters
bool kmpSearch(string &txt, string &pat) {
    int n = txt.length(), m = pat.length();
    if (m > n)
        return false;
    vector<int> lps = buildLps(pat);
    int i = 0, j = 0;
    while (i < n) {
        if (txt[i] == pat[j]) {
            i++;
            j++;
            if (j == m)
                return true;
        } else {
            if (j!= 0) {
                j = lps[j - 1];
            } else {
                i++;
            }
        }
    }
    return false;
}

bool isPatternPresent(string &txt, string &pat) {
    
    // pattern anchored at both start and end: core must match both the prefix
    // and suffix of txt independently, extra characters in between are ignored
    if (pat.size() >= 2 && pat[0] == '^' && pat.back() == '$') {
        string core = pat.substr(1, pat.size() - 2);
        if (core.size() > txt.size())
            return false;
        return txt.substr(0, core.size()) == core &&
               txt.substr(txt.size() - core.size()) == core;
    }
    
    // pattern anchored at the start only
    else if (pat[0] == '^') {
        string core = pat.substr(1);
        if (core.size() > txt.size())
            return false;
        return txt.substr(0, core.size()) == core;
    }
    
    // pattern anchored at the end only
    else if (pat.back() == '$') {
        string core = pat.substr(0, pat.size() - 1);
        if (core.size() > txt.size())
            return false;
        return txt.substr(txt.size() - core.size()) == core;
    }
    
    // no anchors, search as a plain substring using KMP for better time complexity
    else {
        return kmpSearch(txt, pat);
    }
}

int main() {
    string pat = "^coal", txt = "coaltar";

    cout << boolalpha << isPatternPresent(txt, pat) << endl;

    return 0;
}
Java
class GFG {
    
    // builds the longest-prefix-suffix array 
    // used by KMP to skip redundant comparisons
    static int[] buildLps(String pat) {
        int n = pat.length();
        int[] lps = new int[n];
        int length = 0;
        int i = 1;
        while (i < n) {
            if (pat.charAt(i) == pat.charAt(length)) {
                length++;
                lps[i] = length;
                i++;
            } else {
                if (length != 0) {
                    length = lps[length - 1];
                } else {
                    lps[i] = 0;
                    i++;
                }
            }
        }
        return lps;
    }

    // searches for pat as a substring of txt using KMP, 
    // avoiding re-scanning matched characters
    static boolean kmpSearch(String txt, String pat) {
        int n = txt.length(), m = pat.length();
        if (m > n)
            return false;
        int[] lps = buildLps(pat);
        int i = 0, j = 0;
        while (i < n) {
            if (txt.charAt(i) == pat.charAt(j)) {
                i++;
                j++;
                if (j == m)
                    return true;
            } else {
                if (j != 0) {
                    j = lps[j - 1];
                } else {
                    i++;
                }
            }
        }
        return false;
    }

    static boolean isPatternPresent(String txt, String pat) {
        
        // pattern anchored at both start and end: core must 
        // match both the prefix and suffix of txt independently, 
        // extra characters in between are ignored
        if (pat.length() >= 2 && pat.charAt(0) == '^' && pat.charAt(pat.length() - 1) == '$') {
            String core = pat.substring(1, pat.length() - 1);
            if (core.length() > txt.length())
                return false;
            return txt.substring(0, core.length()).equals(core) &&
                   txt.substring(txt.length() - core.length()).equals(core);
        }
        
        // pattern anchored at the start only
        else if (pat.charAt(0) == '^') {
            String core = pat.substring(1);
            if (core.length() > txt.length())
                return false;
            return txt.substring(0, core.length()).equals(core);
        }
        
        // pattern anchored at the end only
        else if (pat.charAt(pat.length() - 1) == '$') {
            String core = pat.substring(0, pat.length() - 1);
            if (core.length() > txt.length())
                return false;
            return txt.substring(txt.length() - core.length()).equals(core);
        }
        
        // no anchors, search as a plain substring using KMP
        // for better time complexity
        else {
            return kmpSearch(txt, pat);
        }
    }

    public static void main(String[] args) {
        String pat = "^coal", txt = "coaltar";

        System.out.println(isPatternPresent(txt, pat));
    }
}
Python
def buildLps(pat):
    
    # builds the longest-prefix-suffix array used by 
    # KMP to skip redundant comparisons
    n = len(pat)
    lps = [0] * n
    length = 0
    i = 1
    while i < n:
        if pat[i] == pat[length]:
            length += 1
            lps[i] = length
            i += 1
        else:
            if length != 0:
                length = lps[length - 1]
            else:
                lps[i] = 0
                i += 1
    return lps

def kmpSearch(txt, pat):
    
    # searches for pat as a substring of txt using KMP, 
    # avoiding re-scanning matched characters
    n, m = len(txt), len(pat)
    if m > n:
        return False
    lps = buildLps(pat)
    i = j = 0
    while i < n:
        if txt[i] == pat[j]:
            i += 1
            j += 1
            if j == m:
                return True
        else:
            if j != 0:
                j = lps[j - 1]
            else:
                i += 1
    return False

def isPatternPresent(txt, pat):
    
    # pattern anchored at both start and end: core 
    # must match both the prefix and suffix of txt 
    # independently, extra characters in between are ignored
    if len(pat) >= 2 and pat[0] == '^' and pat[-1] == '$':
        core = pat[1:-1]
        if len(core) > len(txt):
            return False
        return txt[:len(core)] == core and txt[-len(core):] == core
        
    # pattern anchored at the start only
    elif pat[0] == '^':
        core = pat[1:]
        if len(core) > len(txt):
            return False
        return txt[:len(core)] == core
        
    # pattern anchored at the end only
    elif pat[-1] == '$':
        core = pat[:-1]
        if len(core) > len(txt):
            return False
        return txt[-len(core):] == core
        
    # no anchors, search as a plain substring using KMP 
    # for better time complexity
    else:
        return kmpSearch(txt, pat)

pat = "^coal"
txt = "coaltar"
print(isPatternPresent(txt, pat))
C#
using System;
class GFG {
    
    // builds the longest-prefix-suffix array used 
    // by KMP to skip redundant comparisons
    static int[] buildLps(string pat) {
        int n = pat.Length;
        int[] lps = new int[n];
        int length = 0;
        int i = 1;
        while (i < n) {
            if (pat[i] == pat[length]) {
                length++;
                lps[i] = length;
                i++;
            } else {
                if (length != 0) {
                    length = lps[length - 1];
                } else {
                    lps[i] = 0;
                    i++;
                }
            }
        }
        return lps;
    }

    // searches for pat as a substring of txt using KMP, 
    // avoiding re-scanning matched characters
    static bool kmpSearch(string txt, string pat) {
        int n = txt.Length, m = pat.Length;
        if (m > n)
            return false;
        int[] lps = buildLps(pat);
        int i = 0, j = 0;
        while (i < n) {
            if (txt[i] == pat[j]) {
                i++;
                j++;
                if (j == m)
                    return true;
            } else {
                if (j != 0) {
                    j = lps[j - 1];
                } else {
                    i++;
                }
            }
        }
        return false;
    }

    static bool isPatternPresent(string txt, string pat) {
        
        // pattern anchored at both start and end: core 
        // must match both the prefix and suffix of txt 
        // independently, extra characters in between are ignored
        if (pat.Length >= 2 && pat[0] == '^' && pat[pat.Length - 1] == '$') {
            string core = pat.Substring(1, pat.Length - 2);
            if (core.Length > txt.Length)
                return false;
            return txt.Substring(0, core.Length) == core &&
                   txt.Substring(txt.Length - core.Length) == core;
        }
        
        // pattern anchored at the start only
        else if (pat[0] == '^') {
            string core = pat.Substring(1);
            if (core.Length > txt.Length)
                return false;
            return txt.Substring(0, core.Length) == core;
        }
        
        // pattern anchored at the end only
        else if (pat[pat.Length - 1] == '$') {
            string core = pat.Substring(0, pat.Length - 1);
            if (core.Length > txt.Length)
                return false;
            return txt.Substring(txt.Length - core.Length) == core;
        }
        
        // no anchors, search as a plain substring using 
        // KMP for better time complexity
        else {
            return kmpSearch(txt, pat);
        }
    }

    static void Main() {
        string pat = "^coal", txt = "coaltar";

        Console.WriteLine(isPatternPresent(txt, pat));
    }
}
JavaScript
// builds the longest-prefix-suffix array used 
// by KMP to skip redundant comparisons
function buildLps(pat) {
    const n = pat.length;
    const lps = new Array(n).fill(0);
    let length = 0;
    let i = 1;
    while (i < n) {
        if (pat[i] === pat[length]) {
            length++;
            lps[i] = length;
            i++;
        } else {
            if (length !== 0) {
                length = lps[length - 1];
            } else {
                lps[i] = 0;
                i++;
            }
        }
    }
    return lps;
}

// searches for pat as a substring of txt using KMP, 
// avoiding re-scanning matched characters
function kmpSearch(txt, pat) {
    const n = txt.length, m = pat.length;
    if (m > n)
        return false;
    const lps = buildLps(pat);
    let i = 0, j = 0;
    while (i < n) {
        if (txt[i] === pat[j]) {
            i++;
            j++;
            if (j === m)
                return true;
        } else {
            if (j !== 0) {
                j = lps[j - 1];
            } else {
                i++;
            }
        }
    }
    return false;
}

function isPatternPresent(txt, pat) {
    
    // pattern anchored at both start and end: core
    // must match both the prefix and suffix of txt 
    // independently, extra characters in between are ignored
    if (pat.length >= 2 && pat[0] === '^' && pat[pat.length - 1] === '$') {
        const core = pat.slice(1, -1);
        if (core.length > txt.length)
            return false;
        return txt.slice(0, core.length) === core &&
               txt.slice(txt.length - core.length) === core;
    }
    
    // pattern anchored at the start only
    else if (pat[0] === '^') {
        const core = pat.slice(1);
        if (core.length > txt.length)
            return false;
        return txt.slice(0, core.length) === core;
    }
    
    // pattern anchored at the end only
    else if (pat[pat.length - 1] === '$') {
        const core = pat.slice(0, -1);
        if (core.length > txt.length)
            return false;
        return txt.slice(txt.length - core.length) === core;
    }
    
    // no anchors, search as a plain substring using
    // KMP for better time complexity
    else {
        return kmpSearch(txt, pat);
    }
}

// Driver Code
const pat = "^coal", txt = "coaltar";
console.log(isPatternPresent(txt, pat));

Output
true
Comment