preg_replace($pattern, $replacement, $subject) finds every match of a regular expression in a string and replaces it. preg_replace('/\s+/', ' ', $text) turns every run of spaces, tabs and newlines into a single space.
The original string is not changed; preg_replace() returns a new one. \b marks a word boundary, which is why cats is left alone.
Backreferences: {1} and \1
In the replacement, $1 stands for whatever the first capture group matched, $2 for the second, and $0 for the whole match. Use them to rearrange the matched text.
Write the replacement in single quotes. In double quotes "\1" becomes an octal escape (the byte 0x01) and "${1}" is read as a variable named 1, which is undefined and uses string syntax deprecated since PHP 8.2. '\1' in single quotes works the same as '$1', but $1 is the common spelling.
Remove non-alphanumeric characters
A negated character class, [^...], matches everything that is not listed. Replacing it with '' removes it. For text in other languages, use the Unicode classes \p{L} (any letter) and \p{N} (any digit) with the u modifier, or you will strip é, ü and every Japanese character.
Make a URL slug
Several patterns in a row turn a title into a URL slug. Lowercase first, replace every run of non-alphanumeric characters with one hyphen, then trim hyphens from the ends:
Several patterns, a limit and a count
$pattern and $replacement can be arrays: each pattern is replaced by the replacement at the same index, in order. The fourth argument limits replacements per pattern (-1 means no limit), and the fifth receives how many replacements were made.
Compute the replacement with preg_replace_callback
When the replacement depends on the match, use preg_replace_callback(). It calls your function once per match with the $matches array and inserts whatever the function returns. An arrow function keeps short callbacks on one line.
preg_replace_callback_array() takes an array of pattern => callback pairs when several patterns each need their own function.
Replacement text from a variable
A $ or a backslash in the replacement has a meaning, so a replacement that comes from a user or a database can be mangled. A price of $10 is read as a reference to group 10, which does not exist, and comes out empty:
When neither the search text nor the replacement is a pattern, str_replace() is the simpler and faster choice. To test a pattern before replacing anything, see preg_match().
Frequently Asked Questions
How do I use backreferences in preg_replace?
Refer to capture groups as $1, $2 (or \1) in the replacement: preg_replace('/(\d{4})-(\d{2})-(\d{2})/', '$3/$2/$1', '2026-03-14') returns "14/03/2026". Write the replacement in single quotes, and use ${1} when a digit follows the reference.
How do I remove all non-alphanumeric characters in PHP?
preg_replace('/[^a-zA-Z0-9]/', '', $s) keeps only ASCII letters and digits. To keep letters from every language (é, ü, 日本語), use Unicode classes with the u modifier: preg_replace('/[^\p{L}\p{N}]/u', '', $s).
What is the difference between preg_replace and preg_replace_callback?
preg_replace() takes a fixed replacement string with $1 placeholders. preg_replace_callback() calls a function for each match and uses its return value, so you can compute the replacement: uppercase it, do math on it, or look it up in an array.
Should I use str_replace or preg_replace?
Use str_replace() when you replace fixed text: it is faster and needs no escaping. Use preg_replace() when the text to replace follows a pattern, such as any run of spaces, any digit, or a word boundary.
How do I replace only the first match with preg_replace?
Pass a limit as the fourth argument: preg_replace('/\d+/', '#', 'a1 b2 c3', 1) returns "a# b2 c3". The fifth argument, passed by reference, receives the number of replacements made.