What does preg_match() do?
preg_match() searches $subject for the first match of a Perl-compatible regular expression (PCRE). It returns 1 if the pattern matches and 0 if not, and fills $matches with the full match ($matches[0]) and any capture groups.
Syntax
preg_match(string $pattern, string $subject, array &$matches = null, int $flags = 0, int $offset = 0): int|false
Parameters
$pattern- The regex including delimiters, e.g.'/^\d+$/'. Modifiers follow the closing delimiter:icase-insensitive,uUTF-8,mmultiline,sdot matches newline.$subject- The string to search.$matches- Optional. Filled with the full match at index 0, numbered groups at 1, 2 ..., and named groups by name.$flags-PREG_OFFSET_CAPTURE(also return positions) orPREG_UNMATCHED_AS_NULL.$offset- Byte position to start searching from.
Return value
1 on a match, 0 if there is no match, or false if the pattern is invalid. Compare with === 1 when the difference matters.
preg_match() examples
Every example below shows the exact output it produces. Paste any of them into the editor above (or the online compiler) to run it.
1. Match and capture a number
<?php
$text = "Order #4521 shipped on 2026-03-15";
if (preg_match('/#(\d+)/', $text, $matches)) {
echo "Full match: " . $matches[0] . "\n";
echo "Order number: " . $matches[1] . "\n";
}
var_dump(preg_match('/refund/', $text));
Output:
Full match: #4521 Order number: 4521 int(0)
2. Named capture groups
<?php
$date = "2026-03-15";
if (preg_match('/^(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})$/', $date, $m)) {
echo "Year: {$m['year']}, Month: {$m['month']}, Day: {$m['day']}\n";
}
Output:
Year: 2026, Month: 03, Day: 15
3. Validate input with a regex
<?php
$checks = [
'username' => ['/^[a-z0-9_]{3,16}$/', 'john_doe'],
'zip code' => ['/^\d{5}(-\d{4})?$/', '12345-678'],
'hex color' => ['/^#[0-9a-f]{6}$/i', '#1A2b3C'],
];
foreach ($checks as $label => [$pattern, $value]) {
$ok = preg_match($pattern, $value) === 1;
echo str_pad($label, 10) . $value . " => " . ($ok ? "valid" : "invalid") . "\n";
}
Output:
username john_doe => valid zip code 12345-678 => invalid hex color #1A2b3C => valid
4. Starts with, ends with, case-insensitive
<?php
$text = "mr.sanket";
echo preg_match('/^mr/', $text) ? "starts with mr\n" : "does not start with mr\n";
echo preg_match('/sanket$/', $text) ? "ends with sanket\n" : "does not end with sanket\n";
echo preg_match('/^MR/i', $text) ? "case-insensitive match\n" : "no match\n";
Output:
starts with mr ends with sanket case-insensitive match
5. All matches with preg_match_all()
<?php
$text = "Prices: $4.99, $12.50 and $100";
$count = preg_match_all('/\$(\d+(?:\.\d{2})?)/', $text, $matches);
echo "Found $count prices: " . implode(", ", $matches[1]) . "\n";
Output:
Found 3 prices: 4.99, 12.50, 100
Common mistakes and gotchas
- Delimiters are required:
preg_match("\d+", $s)fails with a warning. Write'/\d+/', or'#...#'when the pattern contains slashes. - Use single quotes for patterns so PHP does not interpret
\dor$inside double-quoted strings. - User input in patterns: escape it with
preg_quote($input, '/'). - Emails and URLs: prefer
filter_var($email, FILTER_VALIDATE_EMAIL)over hand-written regexes. - Only the first match: use
preg_match_all()to find every match.