Summary: in this tutorial, you will learn how to use the regex capturing groups to group and capture parts of a match.
Introduction to the regex capturing groups #
Suppose you have a URI with the following format:
'posts/25'Code language: PHP (php)The URI has a resource name (posts) and id (25). The resource name is a string, while the resource id is an integer.
To match this URI, you can use the following pattern:
\w+/\d+Code language: PHP (php)The following describes the pattern:
\w+– start with one or more words/– contains the forward slash (/).\d+– end with one or more number
Since the pattern contains the forward-slash (/), it’s more readable to use the curly braces as the delimiters to form the regular expression:
"{\w+/\d+}"Code language: PHP (php)The following uses the preg_match() function to match the URI:
<?php
$uri = 'posts/25';
$pattern = '{\w+/\d+}';
if (preg_match($pattern, $uri, $matches)) {
print_r($matches);
}Code language: PHP (php)Here’s the output:
Array
(
[0] => posts/25
)Code language: PHP (php)To get the id from the URI, you can use a capturing group.
A capturing group allows you to get a part of the match as a separate item in the result array.
To create a capturing group, you place part of the pattern in parentheses (...). For example, to capture the id from the URI above, you can use the following regular expression with a capturing group that captures the \d+ part:
'{\w+/(\d+)}'Code language: PHP (php)The following shows the updated code with the capturing group:
<?php
$uri = 'posts/25';
$pattern = '{\w+/(\d+)}';
if (preg_match($pattern, $uri, $matches)) {
print_r($matches);
}Code language: PHP (php)Output:
Array
(
[0] => posts/25
[1] => 25
)Code language: PHP (php)To $matches array now includes both the match and the capturing group. Also, you can have multiple capturing groups like this:
<?php
$uri = 'posts/25';
$pattern = '{(\w+)/(\d+)}';
if (preg_match($pattern, $uri, $matches)) {
print_r($matches);
}Code language: PHP (php)Output:
Array
(
[0] => posts/25
[1] => posts
[2] => 25
)Code language: PHP (php)Regex named groups #
You can put the ?<name> syntax immediately after the opening parenthesis to name a capturing group. For example:
<?php
$uri = 'posts/25';
$pattern = '{(?<controller>\w+)/(?<id>\d+)}';
if (preg_match($pattern, $uri, $matches)) {
print_r($matches);
}Code language: PHP (php)Output:
Array
(
[0] => posts/25
[controller] => posts
[1] => posts
[id] => 25
[2] => 25
)Code language: PHP (php)In this example, we assign the first part of the URI the name controller and the second part the name id.
To get only controller and id from the $matches array, you can pass the $matches array to the array_filter() function like this:
<?php
$uri = 'posts/25';
$pattern = '{(?<controller>\w+)/(?<id>\d+)}';
if (preg_match($pattern, $uri, $matches)) {
$parts = array_filter($matches, fn($key) => is_string($key), ARRAY_FILTER_USE_KEY);
print_r($parts);
}Code language: PHP (php)Output:
Array
(
[controller] => posts
[id] => 25
)Code language: PHP (php)Note that PHP MVC frameworks often use this technique to resolve the URI with a controller and query parameters.
More regex capturing groups example #
Suppose you need to match the following pattern:
controller/year/month/dayCode language: PHP (php)And you want to capture the controller, year, month, and day.
To do that, you use the named groups for capturing groups in a pattern like the following:
<?php
// controller/year/month/day
$uri = 'posts/2021/09/12';
$pattern = '{(?<controller>\w+)/(?<year>\d{4})/(?<month>\d{2})/(?<day>\d{2})}';
if (preg_match($pattern, $uri, $matches)) {
// only get string key
$parts = array_filter($matches, fn($key) => is_string($key), ARRAY_FILTER_USE_KEY);
print_r($parts);
}Code language: PHP (php)Output:
Array
(
[controller] => posts
[year] => 2021
[month] => 09
[day] => 12
)Code language: PHP (php)Reference regex capturing groups in replacement strings #
Suppose you have the name of a person in the first name and last name order e.g., 'John Doe' and you want to reformat it in the reverse order like 'Doe, John':
$name = 'John Doe'; // turns into 'Doe, John'Code language: PHP (php)To match the name format, you can use the following regular expression:
'{\w+ \w+}'Code language: PHP (php)To capture the first name and last name in the matches array, you can put the \w+ pattern in parentheses:
'{(\w+) (\w+)}'Code language: PHP (php)The preg_replace() function allows you to reference a capturing group by its number using the $n format, where n is the capturing group number.
So in the following pattern:
'{(\w+) (\w+)}'Code language: PHP (php)The $1 references the capturing group for the first name and $2 references the capturing group for the last name.
The following shows how to use the preg_replace() function to swap the first name and last name and place a comma between them:
<?php
$name = 'John Doe';
$pattern = '{(\w+) (\w+)}';
echo preg_replace($pattern, '$2, $1', $name);Code language: PHP (php)Output:
Doe, JohnCode language: PHP (php)Summary #
- Use a regex capturing group to get a part of the match as a separate item in the result array.
- Put a part of the pattern in parentheses
(...)to create a capturing group. - Assign a capturing group a name by putting the
?<name>immediately after the opening parentheses(?<name>....) - Use
$nto reference a capturing group, wherenis the capturing group number.