Regular Expressions Mastery: From Beginner to Expert
Regular expressions (regex) are powerful tools for pattern matching and text manipulation. Whether you're validating form inputs, parsing data, or transforming text, mastering regex will make you a more efficient developer.
What Are Regular Expressions?
Regular expressions are sequences of characters that define search patterns. They're used in almost every programming language for tasks like validation, searching, and text manipulation. Think of them as a specialized language for describing text patterns.
Basic Syntax
In JavaScript, regex patterns are enclosed in forward slashes:
// Basic regex pattern
const pattern = /hello/;
// With flags
const patternWithFlags = /hello/gi;
// Using RegExp constructor
const dynamicPattern = new RegExp('hello', 'gi');Regex Flags
Flags modify how the pattern matching works:
g- Global: Find all matches, not just the firsti- Case insensitive: Match regardless of casem- Multiline: ^ and $ match line starts/endss- Dot all: . matches newline charactersu- Unicode: Enable full unicode supporty- Sticky: Match from lastIndex position
const text = 'Hello World, hello universe';
// Without flags
console.log(text.match(/hello/));
// Output: ['Hello'] (first match only, case matters)
// With 'g' flag
console.log(text.match(/hello/g));
// Output: null (case matters, no lowercase 'hello')
// With 'gi' flags
console.log(text.match(/hello/gi));
// Output: ['Hello', 'hello'] (all matches, case insensitive)Character Classes
Basic Character Classes
| Pattern | Description | Example |
|---|---|---|
. | Any character except newline | /c.t/ matches "cat", "cot" |
\d | Any digit (0-9) | /\d+/ matches "123" |
\D | Any non-digit | /\D+/ matches "abc" |
\w | Word character (a-z, A-Z, 0-9, _) | /\w+/ matches "hello_123" |
\W | Non-word character | /\W+/ matches "!@#" |
\s | Whitespace (space, tab, newline) | /\s+/ matches spaces |
\S | Non-whitespace | /\S+/ matches "hello" |
Custom Character Sets
// Match specific characters
const vowels = /[aeiou]/gi;
console.log('hello'.match(vowels));
// Output: ['e', 'o']
// Match ranges
const lowerCase = /[a-z]/g;
const upperCase = /[A-Z]/g;
const alphaNumeric = /[a-zA-Z0-9]/g;
// Negated sets (NOT these characters)
const notVowels = /[^aeiou]/gi;
console.log('hello'.match(notVowels));
// Output: ['h', 'l', 'l']Quantifiers
Quantifiers specify how many times a pattern should match:
| Quantifier | Description | Example |
|---|---|---|
* | 0 or more times | /ab*c/ matches "ac", "abc", "abbc" |
+ | 1 or more times | /ab+c/ matches "abc", "abbc" |
? | 0 or 1 time (optional) | /colou?r/ matches "color", "colour" |
{n} | Exactly n times | /\d{3}/ matches "123" |
{n,} | n or more times | /\d{2,}/ matches "12", "123" |
{n,m} | Between n and m times | /\d{2,4}/ matches "12", "123" |
// Phone number pattern (XXX-XXX-XXXX)
const phonePattern = /\d{3}-\d{3}-\d{4}/;
console.log(phonePattern.test('123-456-7890')); // true
// ZIP code (5 or 9 digits)
const zipPattern = /^\d{5}(-\d{4})?$/;
console.log(zipPattern.test('12345')); // true
console.log(zipPattern.test('12345-6789')); // true
// Password (8-16 chars, must include number)
const passwordPattern = /^(?=.*\d).{8,16}$/;
console.log(passwordPattern.test('password123')); // trueAnchors and Boundaries
| Anchor | Description | Example |
|---|---|---|
^ | Start of string/line | /^Hello/ matches "Hello world" |
$ | End of string/line | /world$/ matches "Hello world" |
\b | Word boundary | /\bcat\b/ matches "cat" not "catch" |
// Must start with uppercase letter
const startsWithUpper = /^[A-Z]/;
console.log(startsWithUpper.test('Hello')); // true
console.log(startsWithUpper.test('hello')); // false
// Must end with punctuation
const endsWithPunc = /[.!?]$/;
console.log(endsWithPunc.test('Hello!')); // true
// Whole word match
const wholeWord = /\bcat\b/;
console.log('the cat sat'.match(wholeWord)); // matches
console.log('catch it'.match(wholeWord)); // no matchGroups and Capturing
Capturing Groups
// Extract parts of a date
const datePattern = /(\d{4})-(\d{2})-(\d{2})/;
const match = '2025-10-25'.match(datePattern);
console.log(match[0]); // "2025-10-25" (full match)
console.log(match[1]); // "2025" (year)
console.log(match[2]); // "10" (month)
console.log(match[3]); // "25" (day)
// Named capturing groups
const namedPattern = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const namedMatch = '2025-10-25'.match(namedPattern);
console.log(namedMatch.groups.year); // "2025"
console.log(namedMatch.groups.month); // "10"
console.log(namedMatch.groups.day); // "25"Non-Capturing Groups
// Non-capturing group (?:...)
const pattern = /(?:Mr|Mrs|Ms)\.\s+(\w+)/;
const match = 'Mr. Smith'.match(pattern);
console.log(match[0]); // "Mr. Smith"
console.log(match[1]); // "Smith" (only captured group)Common Regex Patterns
Email Validation
// Basic email pattern
const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
// More strict email pattern
const strictEmail = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
function validateEmail(email) {
return strictEmail.test(email);
}
console.log(validateEmail('user@example.com')); // true
console.log(validateEmail('invalid.email')); // false
console.log(validateEmail('user@domain')); // falsePhone Number Validation
// US phone number patterns
const usPhone1 = /^\d{3}-\d{3}-\d{4}$/; // 123-456-7890
const usPhone2 = /^\(\d{3}\)\s?\d{3}-\d{4}$/; // (123) 456-7890
const usPhone3 = /^\d{10}$/; // 1234567890
// Flexible phone pattern
const phonePattern = /^[\d\s()+-]+$/;
function validatePhone(phone) {
// Remove all non-digits
const digits = phone.replace(/\D/g, '');
// Check if 10 digits
return digits.length === 10;
}
console.log(validatePhone('(123) 456-7890')); // true
console.log(validatePhone('123-456-7890')); // true
console.log(validatePhone('123 456 7890')); // trueURL Validation
// URL pattern
const urlPattern = /^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)$/;
function validateURL(url) {
return urlPattern.test(url);
}
console.log(validateURL('https://example.com')); // true
console.log(validateURL('http://www.example.com/path')); // true
console.log(validateURL('not-a-url')); // falsePassword Strength
// Strong password requirements:
// - At least 8 characters
// - At least one uppercase letter
// - At least one lowercase letter
// - At least one number
// - At least one special character
function validateStrongPassword(password) {
const minLength = /.{8,}/;
const hasUpper = /[A-Z]/;
const hasLower = /[a-z]/;
const hasNumber = /\d/;
const hasSpecial = /[!@#$%^&*(),.?":{}|<>]/;
return (
minLength.test(password) &&
hasUpper.test(password) &&
hasLower.test(password) &&
hasNumber.test(password) &&
hasSpecial.test(password)
);
}
// Or use lookaheads in a single regex
const strongPassword = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/;
console.log(strongPassword.test('Weak123')); // false
console.log(strongPassword.test('Strong@Pass123')); // trueJavaScript Regex Methods
String Methods
const text = 'The quick brown fox jumps over the lazy dog';
// match() - returns array of matches
console.log(text.match(/the/gi));
// Output: ['The', 'the']
// search() - returns index of first match
console.log(text.search(/fox/));
// Output: 16
// replace() - replaces matches
console.log(text.replace(/the/gi, 'a'));
// Output: "a quick brown fox jumps over a lazy dog"
// replaceAll() - replaces all matches (ES2021)
console.log(text.replaceAll(/the/gi, 'a'));
// split() - splits string by pattern
console.log('a,b;c:d'.split(/[,;:]/));
// Output: ['a', 'b', 'c', 'd']RegExp Methods
const pattern = /\d+/g;
const text = 'I have 2 cats and 3 dogs';
// test() - returns true/false
console.log(/\d/.test(text));
// Output: true
// exec() - returns match details
let match;
while ((match = pattern.exec(text)) !== null) {
console.log(`Found ${match[0]} at index ${match.index}`);
}
// Output:
// Found 2 at index 7
// Found 3 at index 18Advanced Techniques
Lookahead and Lookbehind
// Positive lookahead (?=...)
// Match digits followed by "px"
const pxPattern = /\d+(?=px)/;
console.log('10px 20em 30px'.match(pxPattern));
// Output: ['10'] (doesn't include 'px')
// Negative lookahead (?!...)
// Match digits NOT followed by "px"
const notPxPattern = /\d+(?!px)/;
console.log('10px 20em 30px'.match(notPxPattern));
// Output: ['2'] (from '20em')
// Positive lookbehind (?<=...)
// Match digits preceded by "$"
const pricePattern = /(?<=\$)\d+/;
console.log('$100 and €50'.match(pricePattern));
// Output: ['100']
// Negative lookbehind (?<!...)
// Match digits NOT preceded by "$"
const notPricePattern = /(?<!\$)\d+/;
console.log('$100 and 50'.match(notPricePattern));
// Output: ['0', '0', '5', '0'] (individual digits)Real-World Examples
Credit Card Validation
function validateCreditCard(cardNumber) {
// Remove spaces and dashes
const cleaned = cardNumber.replace(/[\s-]/g, '');
// Check if 13-19 digits
const pattern = /^\d{13,19}$/;
if (!pattern.test(cleaned)) {
return false;
}
// Luhn algorithm check
let sum = 0;
let isEven = false;
for (let i = cleaned.length - 1; i >= 0; i--) {
let digit = parseInt(cleaned[i]);
if (isEven) {
digit *= 2;
if (digit > 9) digit -= 9;
}
sum += digit;
isEven = !isEven;
}
return sum % 10 === 0;
}
console.log(validateCreditCard('4532-1488-0343-6467')); // true (Visa)
console.log(validateCreditCard('1234-5678-9012-3456')); // falseExtract Data from Text
// Extract all email addresses from text
function extractEmails(text) {
const emailPattern = /[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g;
return text.match(emailPattern) || [];
}
const text = `Contact us at support@example.com or sales@example.com`;
console.log(extractEmails(text));
// Output: ['support@example.com', 'sales@example.com']
// Extract hashtags from social media post
function extractHashtags(text) {
const hashtagPattern = /#[a-zA-Z0-9_]+/g;
return text.match(hashtagPattern) || [];
}
const post = 'Learning #JavaScript and #WebDev is fun! #coding';
console.log(extractHashtags(post));
// Output: ['#JavaScript', '#WebDev', '#coding']Performance Tips
Best Practices:
- ✅ Use specific patterns instead of broad ones
- ✅ Compile regex once and reuse
- ✅ Use non-capturing groups when you don't need the match
- ✅ Avoid excessive backtracking with greedy quantifiers
- ❌ Don't use regex for simple string operations
- ❌ Avoid nested quantifiers like
(a+)+
Conclusion
Regular expressions are an essential tool in every developer's toolkit. While they can seem intimidating at first, with practice and understanding of the core concepts, you'll find them invaluable for text processing, validation, and data extraction tasks.
Start with simple patterns and gradually build complexity as you become more comfortable. Remember to test your regex thoroughly and consider edge cases in your validation logic.
Try Our Regex Playground
Test and build regex patterns with live matching and visual highlighting!
Try Regex Playground →