preg_match

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

What Is preg_match() ? In simple terms: preg_match() checks whether a piece of text matches a regular expression. It can also give you the matched text and the parts captured by groups — for example,

What Is preg_match()?

In simple terms: preg_match() checks whether a piece of text matches a regular expression. It can also give you the matched text and the parts captured by groups — for example, the year, month, and day from a date.

Technically: preg_match() searches the subject string for the first match of the pattern. It returns 1 if a match is found, 0 if not, and false if an error occurs. When a third argument is passed, it is filled with the match and its captured groups. Its companion, preg_match_all(), finds all matches.


Syntax

preg_match(
    string $pattern,
    string $subject,
    array &$matches = null,
    int $flags = 0,
    int $offset = 0
): int|false

 

ParameterMeaning
$patternThe regular expression, with delimiters
$subjectThe text to search
$matchesFilled with the results (passed by reference)
$flagsPREG_OFFSET_CAPTURE and/or PREG_UNMATCHED_AS_NULL
$offsetByte position where the search starts

 

Return ValueMeaning
1A match was found
0No match
falseAn error occurred (invalid pattern, invalid UTF-8 with u, backtracking limit)

 


Testing for a Match

Example

<?php
function isValidUsername(string $username): bool
{
    return preg_match('/^[a-z][a-z0-9_]{2,19}$/', $username) === 1;
}

foreach (['asha_dev', 'A', '9lives', 'bala.k', 'charu2026'] as $name) {
    echo str_pad($name, 10) . (isValidUsername($name) ? 'valid' : 'invalid') . "\n";
}

 

Output

asha_dev  valid
A         invalid
9lives    invalid
bala.k    invalid
charu2026 valid

 

How It Works

The pattern requires: a lowercase letter first, then 2–19 lowercase letters, digits, or underscores — 3 to 20 characters in total.

  • A is uppercase and too short.
  • 9lives starts with a digit.
  • bala.k contains a dot, which is not allowed.

The comparison === 1 turns the result into a clean boolean and treats false (an error) as "not valid" instead of letting it pass unnoticed.


Capturing Matches

<?php
preg_match('/(\d+)\s*(kg|g)\b/', 'Package weight: 25 kg', $m);

print_r($m);

 

Output

Array
(
    [0] => 25 kg
    [1] => 25
    [2] => kg
)

 

IndexContains
0The full text matched by the pattern
1The first capturing group: the number
2The second capturing group: the unit

 

If there is no match, $matches becomes an empty array.

Named Groups

<?php
$gstin = '33ABCDE1234F1Z5';
$pattern = '/^(?<state>\d{2})(?<pan>[A-Z]{5}\d{4}[A-Z])(?<entity>[1-9A-Z])Z(?<check>[0-9A-Z])$/';

if (preg_match($pattern, $gstin, $m) === 1) {
    echo "State code: {$m['state']}\n";
    echo "PAN: {$m['pan']}\n";
    echo "Entity number: {$m['entity']}\n";
}

var_dump(preg_match($pattern, '33ABCDE1234F1X5'));

 

Output

State code: 33
PAN: ABCDE1234F
Entity number: 1
int(0)

 

An Indian GSTIN consists of a 2-digit state code (33 is Tamil Nadu), the business's 10-character PAN, an entity number, the letter Z, and a check character. The pattern checks the format and extracts the parts by name. (It does not verify the check character's checksum or that the number is actually registered — that requires additional logic or an official API.)


Flags

PREG_OFFSET_CAPTURE — Where Was It Found?

<?php
preg_match('/world/', 'Hello world', $m, PREG_OFFSET_CAPTURE);

print_r($m);

 

Output

Array
(
    [0] => Array
        (
            [0] => world
            [1] => 6
        )

)

 

Each entry becomes a pair: the matched text and its byte offset in the subject. For UTF-8 text, convert byte offsets to character positions with mb_strlen(substr($subject, 0, $offset)) if needed.

PREG_UNMATCHED_AS_NULL — Consistent Results for Optional Groups

<?php
$pattern = '/(\d+)(?:\.(\d+))?/';

preg_match($pattern, 'Version 8', $plain);
preg_match($pattern, 'Version 8', $withNulls, PREG_UNMATCHED_AS_NULL);

var_dump(count($plain));
var_dump($withNulls);

 

Output

int(2)
array(3) {
  [0]=>
  string(1) "8"
  [1]=>
  string(1) "8"
  [2]=>
  NULL
}

 

The optional minor-version group did not participate in the match. Without the flag, trailing unmatched groups are simply missing from the array (so $plain[2] would cause a warning), and unmatched groups in the middle become empty strings. With PREG_UNMATCHED_AS_NULL, every group is present, and unmatched ones are null — easy to test with ?? or === null.

The $offset Parameter

<?php
preg_match('/\d+/', 'a1b22c333', $m, 0, 3);

echo $m[0] . "\n";

 

Output

22

 

The search starts at byte 3, so the 1 at position 1 is skipped. Note that ^ still refers to the start of the whole string, not the offset; use \G to anchor at the offset.


preg_match_all() — Finding All Matches

preg_match_all(string $pattern, string $subject, array &$matches = null, int $flags = 0, int $offset = 0): int|false

 

It returns the number of matches (or false on error).

Default Order: PREG_PATTERN_ORDER

<?php
$text = 'Pen ₹20, Book ₹249.50, Bag ₹1299';

$count = preg_match_all('/₹(\d+(?:\.\d{2})?)/u', $text, $m);

echo "$count prices\n";
print_r($m[1]);
echo "Total: ₹" . array_sum($m[1]) . "\n";

 

Output

3 prices
Array
(
    [0] => 20
    [1] => 249.50
    [2] => 1299
)
Total: ₹1568.5

 

With the default order, $m[0] holds all full matches and $m[1] holds all values of group 1 — convenient when you need one list per group. (The total is shown without formatting; use number_format() for display.)

PREG_SET_ORDER — One Array per Match

<?php
$header = 'name=Asha; city=Chennai; role=admin';

preg_match_all('/(\w+)=(\w+)/', $header, $matches, PREG_SET_ORDER);

foreach ($matches as [$full, $key, $value]) {
    echo "$key: $value\n";
}

 

Output

name: Asha
city: Chennai
role: admin

 

With PREG_SET_ORDER, each element contains one complete match with its groups — convenient for processing matches one by one, and ideal for destructuring.

FlagStructureBest For
PREG_PATTERN_ORDER (default)$m[group][matchIndex]Collecting all values of a group
PREG_SET_ORDER$m[matchIndex][group]Processing each match as a unit

 


preg_match() vs Other Tools

TaskRecommended
Does the text contain a fixed substring?str_contains()
Does the text start/end with fixed text?str_starts_with() / str_ends_with()
Is this a valid email, URL, IP, or integer?filter_var()
Does the text follow a custom format (codes, IDs, plates)?preg_match()
Extract parts of a formatted stringpreg_match() with groups
Find all occurrences of a patternpreg_match_all()

 


Common Mistakes

Using the Result Loosely

if (preg_match($pattern, $input)) { ... }

 

Effect: Errors (false) and "no match" (0) are treated the same, so a broken pattern silently fails.

Fix: Check === 1, and handle false explicitly where errors are possible.

Expecting All Matches From preg_match()

Effect: Only the first match is returned.

Fix: Use preg_match_all().

Reading Groups That May Be Missing

Effect: "Undefined array key" warnings for optional groups.

Fix: Use PREG_UNMATCHED_AS_NULL and ??.

Validation Without Anchors

Effect: /[a-z]+/ matches "abc!!!" because it finds abc inside.

Fix: Use ^...$ with D, or \A...\z.

Treating Offsets as Character Positions

Effect: Wrong positions for multi-byte text.

Fix: Remember offsets are in bytes; convert with mb_strlen() when needed.


Best Practices

  • Compare the result with === 1 and treat false as an error.
  • Use named groups for readable extraction.
  • Use PREG_UNMATCHED_AS_NULL when patterns contain optional groups.
  • Choose PREG_SET_ORDER when processing each match individually.
  • Prefer string and filter functions for fixed text and standard formats.

Official reference: https\://www.php.net/manual/en/function.preg-match.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 preg_match and get answers drawn from it.

Signed-in readers only.