PHP Regex Functions: preg_match vs preg_replace
Deep dive into PHP regex functions, understand the differences between preg_match and preg_replace, and learn correct usage.
PHP provides powerful PCRE (Perl Compatible Regular Expressions) support, with preg_match and preg_replace being the most commonly used functions. This article will compare these functions in detail, helping you master the correct usage of PHP regular expressions.
PHP Regex Functions Overview
Main Function Categories
| Category | Function | Purpose |
|---|---|---|
| Matching | preg_match() | Perform single match |
| Matching | preg_match_all() | Perform all matches |
| Replace | preg_replace() | Perform regex replacement |
| Replace | preg_replace_callback() | Replace with callback function |
| Split | preg_split() | Split string using regex |
| Filter | preg_filter() | Similar to preg_replace, returns differences |
| Group | preg_grep() | Filter array elements |
Function Selection Guide
Need to match?
→ Match once: preg_match()
→ Match all: preg_match_all()
Need to replace?
→ Simple replacement: preg_replace()
→ Complex logic: preg_replace_callback()
Need to split?
→ preg_split()
Need to filter array?
→ preg_grep()
preg_match() Series
1. preg_match() - Single Match
Basic Usage
<?php
$pattern = '/\d+/';
$subject = "Hello 123 World";
// Returns match count (0 or 1)
$count = preg_match($pattern, $subject, $matches);
if ($count > 0) {
echo "Match found: " . $matches[0] . "\n"; // 123
}
?>
Get Position Information
<?php
$pattern = '/\d+/';
$subject = "abc123def";
// Use PREG_OFFSET_CAPTURE to get position
$count = preg_match($pattern, $subject, $matches, PREG_OFFSET_CAPTURE);
if ($count > 0) {
echo "Match: " . $matches[0][0] . "\n"; // 123
echo "Position: " . $matches[0][1] . "\n"; // 3
}
?>
Use Flags
<?php
// PREG_OFFSET_CAPTURE - Get position
preg_match('/\d+/', "abc123", $matches, PREG_OFFSET_CAPTURE);
// PREG_UNMATCHED_AS_NULL - Unmatched groups return null
preg_match('/(\d+)(\w+)?/', "123", $matches, PREG_UNMATCHED_AS_NULL);
// $matches[2] is null instead of empty string
?>
2. preg_match_all() - Global Match
Basic Usage
<?php
$pattern = '/\d+/';
$subject = "a1b2c3d4";
// Returns match count
$count = preg_match_all($pattern, $subject, $matches);
echo "Match count: " . $count . "\n"; // 4
print_r($matches[0]); // ["1", "2", "3", "4"]
?>
Sort Order
<?php
$pattern = '/(\d)(\w+)/';
$subject = "1a 2b 3c";
// PREG_PATTERN_ORDER (default) - Sort by groups
preg_match_all($pattern, $subject, $matches, PREG_PATTERN_ORDER);
print_r($matches);
/*
Array (
[0] => Array ([0] => 1a [1] => 2b [2] => 3c)
[1] => Array ([0] => 1 [1] => 2 [2] => 3)
[2] => Array ([0] => a [1] => b [2] => c)
)
*/
// PREG_SET_ORDER - Sort by match sets
preg_match_all($pattern, $subject, $matches, PREG_SET_ORDER);
print_r($matches);
/*
Array (
[0] => Array ([0] => 1a [1] => 1 [2] => a)
[1] => Array ([0] => 2b [1] => 2 [2] => b)
[2] => Array ([0] => 3c [1] => 3 [2] => c)
)
*/
?>
Get Position Information
<?php
$pattern = '/\d+/';
$subject = "a1b2c3";
preg_match_all($pattern, $subject, $matches, PREG_OFFSET_CAPTURE);
print_r($matches[0]);
/*
Array (
[0] => Array ([0] => 1 [1] => 1)
[1] => Array ([0] => 2 [1] => 3)
[2] => Array ([0] => 3 [1] => 5)
)
*/
?>
3. preg_match() vs preg_match_all()
Usage Scenario Comparison
<?php
$email = "[email protected], [email protected]";
// Only need to know if email exists
if (preg_match('/[\w.+-]+@[\w.-]+\.[a-z]{2,}/', $email)) {
echo "Contains email address\n";
}
// Need to extract all emails
preg_match_all('/[\w.+-]+@[\w.-]+\.[a-z]{2,}/', $email, $matches);
print_r($matches[0]); // ["[email protected]", "[email protected]"]
?>
Performance Comparison
<?php
$text = str_repeat("test 123 ", 1000);
// preg_match() - Only checks first match
preg_match('/\d+/', $text); // Fast
// preg_match_all() - Finds all matches
preg_match_all('/\d+/', $text, $matches); // Slower, needs to traverse entire string
?>
preg_replace() Series
1. preg_replace() - Basic Replacement
Basic Usage
<?php
$pattern = '/\d+/';
$replacement = '[number]';
$subject = "Price: 100, 200, 300";
$result = preg_replace($pattern, $replacement, $subject);
echo $result; // Price: [number], [number], [number]
?>
Limit Replacement Count
<?php
$pattern = '/a/';
$replacement = 'b';
$subject = "a-a-a-a";
// Only replace first two
$result = preg_replace($pattern, $replacement, $subject, 2);
echo $result; // b-b-a-a
?>
Use Group References
<?php
$pattern = '/(\d{4})-(\d{2})-(\d{2})/';
$replacement = '$2/$3/$1'; // Reference groups
$subject = "2024-01-25";
$result = preg_replace($pattern, $replacement, $subject);
echo $result; // 01/25/2024
?>
Replace Multiple Patterns
<?php
$patterns = ['/apple/', '/banana/', '/orange/'];
$replacements = ['apple', 'banana', 'orange'];
$subject = "I like apple, banana, and orange";
$result = preg_replace($patterns, $replacements, $subject);
echo $result; // I like apple, banana, and orange
?>
2. preg_replace_callback() - Callback Replacement
Basic Usage
<?php
$pattern = '/\d+/';
$subject = "Price: 100, 200, 300";
$result = preg_replace_callback($pattern, function($matches) {
$num = intval($matches[0]);
return $num * 0.9; // Apply 10% discount
}, $subject);
echo $result; // Price: 90, 180, 270
?>
Complex Logic Replacement
<?php
$pattern = '/#(\w+)/';
$subject = "Check out #PHP and #Regex";
$result = preg_replace_callback($pattern, function($matches) {
$tag = $matches[1];
return "<a href='/tag/$tag'>#$tag</a>";
}, $subject);
echo $result; // Check out <a href='/tag/PHP'>#PHP</a> and <a href='/tag/Regex'>#Regex</a>
?>
Use Array Callback
<?php
class TagReplacer {
public function replace($matches) {
return strtoupper($matches[1]);
}
}
$pattern = '/(\w+)/';
$subject = "hello world";
$replacer = new TagReplacer();
$result = preg_replace_callback($pattern, [$replacer, 'replace'], $subject);
echo $result; // HELLO WORLD
?>
3. preg_replace() vs preg_replace_callback()
Simple Replacement - preg_replace()
<?php
// Simple string replacement
$result = preg_replace('/\d+/', 'number', '123 456');
?>
Complex Logic - preg_replace_callback()
<?php
// Need calculation or conditional logic
$result = preg_replace_callback('/\d+/', function($matches) {
$num = intval($matches[0]);
if ($num > 100) {
return $num * 0.8;
}
return $num;
}, '50 150 200');
?>
Other Important Functions
1. preg_split() - Split String
Basic Usage
<?php
$pattern = '/[,;|]/';
$subject = "apple,banana;orange|grape";
$parts = preg_split($pattern, $subject);
print_r($parts); // ["apple", "banana", "orange", "grape"]
?>
Limit Split Count
<?php
$pattern = '/[,;]/';
$subject = "a,b,c,d,e";
$parts = preg_split($pattern, $subject, 2);
print_r($parts); // ["a", "b,c,d,e"]
?>
Keep Whitespace
<?php
$pattern = '/\s+/';
$subject = "a b c";
$parts = preg_split($pattern, $subject, -1, PREG_SPLIT_NO_EMPTY);
print_r($parts); // ["a", "b", "c"]
?>
2. preg_grep() - Filter Array
Basic Usage
<?php
$pattern = '/^\d+$/';
$array = ["123", "abc", "456", "def"];
// Matched elements
$matched = preg_grep($pattern, $array);
print_r($matched); // ["123", "456"]
// Non-matched elements (use PREG_GREP_INVERT)
$notMatched = preg_grep($pattern, $array, PREG_GREP_INVERT);
print_r($notMatched); // ["abc", "def"]
?>
3. preg_filter() - Conditional Replacement
<?php
$pattern = '/\d+/';
$replacement = 'number';
$subjects = ["test 123", "no numbers", "456 end"];
// Only replace strings containing matches
$result = preg_filter($pattern, $replacement, $subjects);
print_r($result); // ["test number", "456 end"]
?>
Practical Examples
Example 1: Validate Email
<?php
function isValidEmail($email) {
$pattern = '/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/';
return preg_match($pattern, $email) === 1;
}
var_dump(isValidEmail("[email protected]")); // true
var_dump(isValidEmail("invalid.email")); // false
?>
Example 2: Extract All Emails
<?php
function extractEmails($text) {
$pattern = '/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/';
preg_match_all($pattern, $text, $matches);
return $matches[0];
}
$text = "Contact: [email protected], [email protected]";
print_r(extractEmails($text));
// ["[email protected]", "[email protected]"]
?>
Example 3: Clean HTML Tags
<?php
function stripHTML($html) {
$pattern = '/<[^>]+>/';
return preg_replace($pattern, '', $html);
}
$html = "<p>Hello <b>World</b>!</p>";
echo stripHTML($html); // Hello World!
?>
Example 4: BBCode Parser
<?php
function parseBBCode($text) {
// [b]bold[/b]
$text = preg_replace('/\[b\](.*?)\[\/b\]/s', '<b>$1</b>', $text);
// [i]italic[/i]
$text = preg_replace('/\[i\](.*?)\[\/i\]/s', '<i>$1</i>', $text);
// [url=link]text[/url]
$text = preg_replace('/\[url=([^\]]+)\](.*?)\[\/url\]/s', '<a href="$1">$2</a>', $text);
return $text;
}
$bbcode = "[b]bold[/b] and [i]italic[/i]";
echo parseBBCode($bbcode);
// <b>bold</b> and <i>italic</i>
?>
Example 5: Phone Number Masking
<?php
function maskPhone($phone) {
$pattern = '/(\d{3})\d{4}(\d{4})/';
return preg_replace($pattern, '$1****$2', $phone);
}
echo maskPhone("13812345678"); // 138****5678
?>
Example 6: Extract URL Parameters
<?php
function extractURLParams($url) {
$pattern = '/[?&]([^=]+)=([^&]+)/';
preg_match_all($pattern, $url, $matches);
$params = [];
foreach ($matches[1] as $index => $key) {
$params[$key] = $matches[2][$index];
}
return $params;
}
$url = "https://example.com?name=John&age=30&city=NYC";
print_r(extractURLParams($url));
// ["name" => "John", "age" => "30", "city" => "NYC"]
?>
Example 7: Markdown Conversion
<?php
function convertMarkdown($text) {
# Headers
$text = preg_replace('/^# (.+)$/m', '<h1>$1</h1>', $text);
$text = preg_replace('/^## (.+)$/m', '<h2>$1</h2>', $text);
$text = preg_replace('/^### (.+)$/m', '<h3>$1</h3>', $text);
# Bold
$text = preg_replace('/\*\*(.+?)\*\*/', '<strong>$1</strong>', $text);
# Italic
$text = preg_replace('/\*(.+?)\*/', '<em>$1</em>', $text);
# Links
$text = preg_replace('/\[([^\]]+)\]\(([^)]+)\)/', '<a href="$2">$1</a>', $text);
return $text;
}
$markdown = "**bold** and *italic* [link](http://example.com)";
echo convertMarkdown($markdown);
// <strong>bold</strong> and <em>italic</em> <a href="http://example.com">link</a>
?>
Best Practices
1. Use Delimiters
<?php
// Good practice: Use delimiters
$pattern = '/\d+/';
// Can also use other characters
$pattern = '#\d+#';
$pattern = '!\d+!';
?>
2. Use Single Quotes
<?php
// Good practice: Use single quotes (safer)
$pattern = '/\d+/';
// Bad practice: Use double quotes (might accidentally parse variables)
$pattern = "/\d+/";
?>
3. Check Return Values
<?php
// Good practice: Check return values
if (preg_match('/\d+/', $text, $matches)) {
echo $matches[0];
}
// Bad practice: Don't check
preg_match('/\d+/', $text, $matches);
echo $matches[0]; // Might be undefined index
?>
4. Use Non-Greedy Matching
<?php
// Good practice: Non-greedy
$pattern = '/<div>.*?<\/div>/';
// Bad practice: Greedy
$pattern = '/<div>.*<\/div>/';
?>
5. Pre-compile Patterns (Cache)
<?php
// Good practice: Pre-compile patterns
class RegexCache {
private static $cache = [];
public static function get($pattern) {
if (!isset(self::$cache[$pattern])) {
self::$cache[$pattern] = $pattern;
}
return self::$cache[$pattern];
}
}
$pattern = RegexCache::get('/\d+/');
?>
Performance Optimization
1. Avoid Repeated Matching
<?php
// Bad practice: Match multiple times
if (preg_match('/\d+/', $text)) {
preg_match_all('/\d+/', $text, $matches);
}
// Good practice: Match once
preg_match_all('/\d+/', $text, $matches);
if (!empty($matches[0])) {
// Process results
}
?>
2. Use More Specific Patterns
<?php
// Efficient
$pattern = '/\d{3}-\d{4}-\d{4}/';
// Inefficient
$pattern = '/.+/';
?>
3. Limit Match Scope
<?php
// Good practice: Specify start and end
$pattern = '/^\d+$/';
// Bad practice: Search in entire string
$pattern = '/\d+/';
?>
Common Errors
1. Forgetting to Escape
<?php
// Error: No escape for backslash
$pattern = '/\d+/';
// Correct: Use single quotes
$pattern = '/\d+/';
// Or escape
$pattern = "/\\d+/";
?>
2. Confusing preg_match and preg_match_all
<?php
// Error: Want all matches but used preg_match
preg_match('/\d+/', "1 2 3", $matches);
echo $matches[0]; // Only "1"
// Correct: Use preg_match_all
preg_match_all('/\d+/', "1 2 3", $matches);
print_r($matches[0]); // ["1", "2", "3"]
?>
3. Incorrectly Using Replacement References
<?php
// Error: Using variable reference in double quotes
$pattern = '/(\d+)/';
$replacement = "$1"; // Might error
// Correct: Use single quotes or escape
$replacement = '$1';
?>
Summary
| Function | Purpose | Return Value |
|---|---|---|
preg_match() | Single match | 0 or 1 |
preg_match_all() | Global match | Match count |
preg_replace() | Regex replacement | Replaced string |
preg_replace_callback() | Callback replacement | Replaced string |
preg_split() | Split string | Array |
preg_grep() | Filter array | Matched array |
preg_filter() | Conditional replacement | Replaced array |
Selection Guide:
- Validation →
preg_match() - Extraction →
preg_match()orpreg_match_all() - Simple replacement →
preg_replace() - Complex replacement →
preg_replace_callback() - Splitting →
preg_split() - Filtering arrays →
preg_grep()
Master these functions, and you can efficiently handle various text operations in PHP!
Use our online Regex Tester to test PHP regex patterns!
About the Author
The Regex Master Team consists of experienced developers and technical writers dedicated to simplifying regular expressions for everyone. We ensure all patterns are rigorously tested and verified to provide accurate, production-ready solutions.
Try It: Regex Tester
Use our interactive regex tester to experiment with the patterns you learned in this article. Test your regular expressions in real-time and see immediate results.