// Inspired by https://www.cs.princeton.edu/courses/archive/spr09/cos333/beautiful.html const matchHere = (pattern, text) => { if (pattern.length === 0) return true; // If pattern ends with $, match end of string if (pattern[0] === '$' && pattern.length === 1) return text.length === 0; // If next char is '*', match zero or more occurrences of prev char if (pattern[1] === '*') return matchStar(pattern[0], pattern.slice(2), text); // Match . or literal character if (text.length !== 0 && (pattern[0] === '.' || pattern[0] === text[0])) { return matchHere(pattern.slice(1), text.slice(1)); } return false; }; const matchStar = (prevChar, pattern, text) => { // Try matching zero occurrences first if (matchHere(pattern, text)) return true; // Then, match one or more occurrences of prevChar while (text.length > 0 && (text[0] === prevChar || prevChar === '.')) { text = text.slice(1); if (matchHere(pattern, text)) return true; } return false; }; const match = (pattern, text) => { // Handle ^ anchor at the beginning if (pattern[0] === '^') { return matchHere(pattern.slice(1), text); } // Otherwise, check the entire string for (let i = 0; i <= text.length; i++) { if (matchHere(pattern, text.slice(i))) return true; } return false; }; const assertEqual = (actual, expected, testName) => console.log(actual === expected ? `Passed: ${testName}` : `Failed: ${testName}. Expected ${expected} but got ${actual}`); assertEqual(match("ab*c", "ac"), true, "Star match 'ab*c' vs 'ac' (zero occurrences)"); assertEqual(match("ab*c", "abbbc"), true, "Star match 'ab*c' vs 'abbbc' (multiple occurrences)"); assertEqual(match("^ab.*c$", "abc"), true, "Complex match '^ab.*c$' vs 'abc'"); assertEqual(match("^ab.*c$", "abcd"), false, "Complex mismatch '^ab.*c$' vs 'abcd'");