Article Categories
- All Categories
-
Data Structure
-
Networking
-
RDBMS
-
Operating System
-
Java
-
MS Excel
-
iOS
-
HTML
-
CSS
-
Android
-
Python
-
C Programming
-
C++
-
C#
-
MongoDB
-
MySQL
-
Javascript
-
PHP
-
Economics & Finance
Regular Expression Matching in JavaScript
Regular expression matching is a fundamental concept in computer science where we match an input string against a pattern containing special characters. In JavaScript, we can implement custom regex matching using dynamic programming to handle patterns with . (any character) and * (zero or more occurrences).
Problem Definition
Given an input string str and a pattern p, implement regular expression matching with support for:
.? Matches any single character*? Matches zero or more of the preceding element
The matching must cover the entire input string (not partial matching).
Constraints
strcontains only lowercase letters a-z (can be empty)pcontains lowercase letters a-z,., and*(can be empty)
Algorithm Overview
We use dynamic programming with a 2D array where match[i][j] represents whether the first i characters of the string match the first j characters of the pattern.
Implementation
const regexMatching = (str, p) => {
const ZERO_OR_MORE_CHARS = '*';
const ANY_CHAR = '.';
// Create 2D DP table
const match = Array(str.length + 1).fill(null).map(() => {
return Array(p.length + 1).fill(null);
});
// Base case: empty string matches empty pattern
match[0][0] = true;
// Handle patterns like a*, a*b*, a*b*c* (empty string cases)
for (let col = 1; col <= p.length; col += 1) {
const patternIndex = col - 1;
if (p[patternIndex] === ZERO_OR_MORE_CHARS) {
match[0][col] = match[0][col - 2];
} else {
match[0][col] = false;
}
}
// Empty pattern cannot match non-empty string
for (let row = 1; row <= str.length; row += 1) {
match[row][0] = false;
}
// Fill the DP table
for (let row = 1; row <= str.length; row += 1) {
for (let col = 1; col <= p.length; col += 1) {
const stringIndex = row - 1;
const patternIndex = col - 1;
if (p[patternIndex] === ZERO_OR_MORE_CHARS) {
// * can match zero occurrences
if (match[row][col - 2] === true) {
match[row][col] = true;
// * can match one or more occurrences
} else if (
(p[patternIndex - 1] === str[stringIndex] ||
p[patternIndex - 1] === ANY_CHAR) &&
match[row - 1][col] === true
) {
match[row][col] = true;
} else {
match[row][col] = false;
}
} else if (
p[patternIndex] === str[stringIndex] ||
p[patternIndex] === ANY_CHAR
) {
match[row][col] = match[row - 1][col - 1];
} else {
match[row][col] = false;
}
}
}
return match[str.length][p.length];
};
// Test cases
console.log(regexMatching('aab', 'c*a*b')); // true
console.log(regexMatching('aa', 'a')); // false
console.log(regexMatching('aa', 'a*')); // true
console.log(regexMatching('ab', '.*')); // true
true false true true
How It Works
The algorithm handles three main cases:
- Star (*) character: Can match zero occurrences (skip 2 positions) or multiple occurrences
- Dot (.) character: Matches any single character
- Exact match: Character in pattern must equal character in string
Time and Space Complexity
| Complexity | Value | Explanation |
|---|---|---|
| Time | O(m × n) | Fill m×n DP table |
| Space | O(m × n) | 2D array storage |
Where m = string length, n = pattern length.
Conclusion
Regular expression matching using dynamic programming efficiently handles patterns with * and . characters. The algorithm builds a truth table to determine if the entire string matches the given pattern, making it suitable for implementing custom regex engines.
