PHP RegEx

Ma Mariya Vinciya Updated 21 Oct 2026
7 min read ·Lesson 156 of 174
In this post

What Is a Regular Expression? In simple terms: A regular expression (regex) is a pattern that describes what text should look like — for example, "exactly ten digits starting with 6, 7, 8, or 9" or "a

What Is a Regular Expression?

In simple terms: A regular expression (regex) is a pattern that describes what text should look like — for example, "exactly ten digits starting with 6, 7, 8, or 9" or "a word that starts with #". PHP can use such a pattern to check, find, extract, replace, or split text.

Technically: PHP's regex functions use the PCRE2 library (Perl Compatible Regular Expressions), which is built into PHP and always available. Functions in this family start with preg_. A pattern is written as a string with delimiters around it and optional modifiers after it.

Why Regular Expressions Are Useful

Simple string functions (str_contains(), str_replace(), explode()) work with fixed text. Regular expressions work with patterns:

TaskWithout RegexWith Regex
"Does the text contain php?"str_contains()Not needed
"Is this a valid Indian mobile number?"Many checks on length, digits, first digit/^[6-9]\d{9}$/
"Extract all hashtags from a post"Manual character-by-character parsing/#(\w+)/
"Collapse any run of whitespace into one space"Loopspreg_replace('/\s+/', ' ', $text)

 

Use string functions for fixed text, and regular expressions when the text follows a pattern.


Anatomy of a Pattern

   /^[6-9]\d{9}\$/i

   │└────┬─────┘│└── modifier(s), e.g. i \= case-insensitive

   │ │ └─── closing delimiter

   │ └────────── the pattern itself

   └──────────────── opening delimiter

 

  • Delimiters mark the start and end of the pattern. / is most common, but any non-alphanumeric, non-whitespace character except backslash works, such as # or ~. Brackets can also be used in pairs: {...}, (...), [...].
  • Modifiers after the closing delimiter change how the pattern is applied (see RegEx Modifiers).
  • Write patterns in single-quoted strings, so PHP does not interpret backslashes and $ before the regex engine sees them.

Choosing a different delimiter avoids escaping when the pattern contains /:

<?php

var_dump(preg_match('/^https:\/\//', 'https\://gocourse.in'));

var_dump(preg_match('#^https\://#', 'https\://gocourse.in'));

 

Output

int(1)

int(1)

 

Both patterns are equivalent; the second is easier to read.


The preg_* Functions

FunctionPurposeReturnsLesson
preg_match()Test a pattern / get the first match1, 0, or false on errorpreg_match
preg_match_all()Find all matchesNumber of matches, or falsepreg_match
preg_replace()Replace matchesNew string (or array)preg_replace
preg_replace_callback()Replace using a functionNew stringpreg_replace
preg_split()Split a string by a patternArray of piecespreg_split
preg_grep()Filter an array by a patternMatching elementsPHP RegEx Functions
preg_quote()Escape special characters in textEscaped stringPHP RegEx Functions
preg_last_error() / preg_last_error_msg()Get the last errorError code / message (8.0+)PHP RegEx Functions

 


First Examples

Testing for a Match

<?php

var_dump(preg_match('/php/i', 'I love PHP'));

var_dump(preg_match('/python/i', 'I love PHP'));

 

Output

int(1)

int(0)

 

preg_match() returns 1 if the pattern is found and 0 if not. The i modifier makes the match case-insensitive. Because it can also return false on error, compare with === 1 when using it as a condition.

Validating a Format

<?php

function isIndianMobile(string \$number): bool

{

    return preg_match('/^[6-9]\d{9}\$/', \$number) \=== 1;

}

 

foreach (['9876543210', '1234567890', '98765', '98765432101'] as \$number) {

    echo \$number . ': ' . (isIndianMobile(\$number) ? 'valid' : 'invalid') . "\n";

}

 

Output

9876543210: valid

1234567890: invalid

98765: invalid

98765432101: invalid

 

Reading the Pattern

PartMeaning
^Start of the string
[6-9]One character in the range 6–9
\d{9}Exactly nine digits
$End of the string

 

Without ^ and $, the pattern would also match a valid number inside longer text, such as abc9876543210xyz. Anchors are essential for validation. (Strictly, $ also allows a trailing newline; use \z or the D modifier for exact end-of-string matching — see RegEx Patterns.)

Finding All Matches

<?php

\$text \= 'Order 12 has 3 items costing 450';

 

\$count \= preg_match_all('/\d+/', \$text, \$matches);

 

echo "Found \$count numbers: " . implode(', ', \$matches[0]) . "\n";

 

Output

Found 3 numbers: 12, 3, 450

 

\d+ means "one or more digits". preg_match_all() stores every match in $matches[0].

Replacing and Splitting

<?php

echo preg_replace('/\s+/', ' ', "too many \n\t spaces") . "\n";

 

print_r(preg_split('/[,;\s]+/', 'php, mysql;laravel html'));

 

Output

too many spaces

Array

(

    [0] \=> php

    [1] \=> mysql

    [2] \=> laravel

    [3] \=> html

)

 

  • \s+ matches any run of whitespace (spaces, tabs, newlines), which is replaced by a single space.
  • [,;\s]+ matches any run of commas, semicolons, or whitespace, so the string can be split no matter which separators were used.

Escaping User Input With preg_quote()

When building a pattern from user input, special characters in the input must be escaped; otherwise, they are interpreted as regex syntax:

<?php

\$search \= 'C++ (advanced)';

 

\$pattern \= '/' . preg_quote(\$search, '/') . '/i';

 

echo \$pattern . "\n";

var_dump(preg_match(\$pattern, 'Course: c++ (Advanced) batch'));

 

Output

/C\+\+ \(advanced\)/i

int(1)

 

preg_quote() escapes every character with a special meaning, and its second argument also escapes the delimiter. Without it, + and ( would be treated as a quantifier and a group, and the search would fail or produce an error.


Handling Errors

An invalid pattern does not throw an exception. PHP emits a warning and the function returns false:

<?php

\$result \= preg_match('/[a-z/', 'abc');

 

var_dump(\$result);

echo preg_last_error_msg() . "\n";

 

Output

PHP Warning: preg_match(): Compilation failed: missing terminating ] for character class at offset 4 in /path/script.php on line 2

bool(false)

Internal error

 

  • The pattern is missing the closing ] of a character class, so PCRE cannot compile it.
  • false is easy to confuse with 0 (no match) in a loose condition like if (preg_match(...)). Use === 1 for "matched".
  • preg_last_error_msg() (PHP 8.0+) describes the last error. Runtime errors, such as exceeding the backtracking limit or invalid UTF-8 input with the u modifier, are also reported through it.

Catastrophic Backtracking

Some patterns with nested repetition, such as /(a+)+$/, can take an enormous amount of time on certain inputs, because the engine tries an exponential number of ways to match. PHP limits this (pcre.backtrack_limit), and the function returns false with an error such as "Backtrack limit exhausted". Avoid nested quantifiers on the same characters, and keep patterns specific.


When Not to Use Regular Expressions

TaskBetter Tool
Check for fixed textstr_contains(), str_starts_with(), str_ends_with()
Replace fixed textstr_replace()
Split on a single fixed separatorexplode()
Validate emails, URLs, IPs, integersfilter_var() with validation filters (see PHP Form URL/E-mail)
Parse HTML or XMLDOMDocument (or Dom\HTMLDocument in PHP 8.4+)
Parse JSON or CSVjson_decode(), fgetcsv() / str_getcsv()

 

String functions are faster and easier to read for simple tasks, and dedicated parsers handle complex formats correctly where a regex would fail on edge cases.


Practical Example: Extracting Hashtags and Mentions

<?php

function extractTags(string \$post): array

{

    preg_match_all('/#(\w+)/', \$post, \$hashtags);

    preg_match_all('/@(\w+)/', \$post, \$mentions);

 

    return [

        'hashtags' \=> array_values(array_unique(array_map('strtolower', \$hashtags[1]))),

        'mentions' \=> array_values(array_unique(\$mentions[1])),

    ];

}

 

\$post \= 'Learning #PHP with @asha and @bala_dev! #webdev #php8 #php';

 

print_r(extractTags(\$post));

 

Output

Array

(

    [hashtags] \=> Array

        (

            [0] \=> php

            [1] \=> webdev

            [2] \=> php8

        )

 

    [mentions] \=> Array

        (

            [0] \=> asha

            [1] \=> bala_dev

        )

 

)

 

Step-by-Step Explanation

  1. #(\w+) matches # followed by one or more word characters (letters, digits, underscore). The parentheses create a capturing group, so $hashtags[1] contains just the tag text without #.
  2. @(\w+) does the same for mentions.
  3. Hashtags are lowercased and de-duplicated, so #PHP and #php count as one tag.
  4. array_values() re-indexes the results after array_unique().

Note that \w matches only ASCII letters by default; for hashtags in other scripts (such as Tamil), use the u modifier and Unicode classes, covered in RegEx Patterns and RegEx Modifiers.


Common Mistakes

Forgetting Delimiters

Effect: preg_match('^\d+$', ...) produces a "Delimiter must not be alphanumeric or backslash" warning (the exact wording differs slightly between versions).

Fix: Wrap the pattern: '/^\d+$/'.

Missing Anchors in Validation

Effect: '/\d{6}/' accepts 'abc123456xyz'.

Fix: Use ^ and $ (or \A and \z).

Using Double-Quoted Patterns

Effect: PHP interprets \$, \n, or variables before the regex engine sees them.

Fix: Use single quotes.

Inserting User Input Unescaped

Effect: Broken patterns, errors, or unintended matches.

Fix: preg_quote($input, '/').

Treating false as "No Match"

Effect: Pattern errors go unnoticed.

Fix: Check === 1 for a match and handle false as an error.


Best Practices

  • Use regular expressions for patterns and string functions for fixed text.
  • Anchor validation patterns and keep them as specific as possible.
  • Write patterns in single quotes and choose delimiters that avoid escaping.
  • Escape dynamic text with preg_quote().
  • Check for errors with === false and preg_last_error_msg().

Official reference: https\://www.php.net/manual/en/book.pcre.php

 

0 Comments

Reviewed before they appear

No comments yet.

PHP
PHP Home PHP Switch PHP Match Alternative Syntax PHP Loops While Loop Do While Loop For Loop Foreach Loop Nested Loops Break Statement PHP Intro PHP Install PHP Built-in Web Server PHP Syntax PHP Tags PHP and HTML PHP Comments PHP Multiline Comments PHP Variables Variables Scope PHP Casting Logical Operators Null Coalescing Operator Spaceship Operator Operator Precedence Continue Statement Modify Strings PHP If...Else...Elseif PHP If Modify Strings PHP If Operators PHP Functions Concatenate Strings PHP If...Else User-defined Functions Slicing Strings PHP Shorthand if Escape Characters Default Argument Values PHP Nested if Pass by Reference String Interpolation Named Arguments PHP File Upload Variadic Functions Return Values Search in Strings Multibyte Strings Type Declarations in Functions PHP Numbers PHP Math PHP Floats PHP Random Numbers PHP Constants PHP Properties PHP Methods PHP Constructor Constructor Property Promotion PHP Cookies PHP Destructor PHP Access Modifiers Readonly Properties PHP Sessions PHP Inheritance Method Overriding PHP Filters The final Keyword CSRF Protection PHP Filters Advanced Session Security Secure Cookies PHP Magic Constants File Upload Security PHP Callback Functions PHP Operators Filesystem Security PHP JSON Arithmetic Operators Error Reporting in Production Hiding PHP Assignment Operators PHP Configuration (php.ini) Comparison Operators PHP Command Line (CLI) PHP Exceptions Increment / Decrement Operators Migrating to PHP 8 PHP Form Validation PHP Form Required PHP Form URL/E-mail Error Handling Form Input Sanitizing Escaping Output (htmlspecialchars) Custom Error Handler Checkbox, Radio and Select Inputs Sticky Forms PHP Form Complete PHP Date and Time Date Formatting Error Logging HTTP Headers and Redirects Output Buffering Sending Email PHP cURL Consuming REST APIs PHP Generators AJAX PHP AJAX Database AJAX XML AJAX Live Search AJAX Poll AJAX with JSON Security Introduction Password Hashing SQL Injection Prevention XSS Prevention Garbage Collection Project: Simple Blog PHP What is OOP PHP Classes/Objects The $this Keyword Access Array Items Update Array Items Add Array Items Remove Array Items Sorting Arrays Multidimensional Arrays Array Destructuring Array Spread Operator Search in Arrays Merge Arrays PHP Abstract Classes PHP Interfaces Polymorphism PHP Traits PHP Static Methods PHP Static Properties Late Static Binding Magic Methods Object Cloning MySQL Database MySQL Connect MySQL Create DB MySQL Create Table MySQL Insert Data MySQL Get Last ID MySQL Insert Multiple MySQL Prepared MySQL Select Data MySQL Where Debugging PHP Project: Image Upload Gallery $_SESSION $_ENV PHP RegEx RegEx Patterns Heredoc and Nowdoc RegEx Modifiers preg_match preg_replace preg_split PHP RegEx Functions Nullable Types Mixed and Never Types Nullsafe Operator PHP Attributes PHP Fibers Readonly Classes Property Hooks (PHP 8.4) Asymmetric Visibility (PHP 8.4) Reflection API SPL Data Structures Composer
Ask about this post
AI Ask about this post

Ask questions about PHP RegEx and get answers drawn from it.

Signed-in readers only.