PHP 正则表达式完全指南
·
PHP 正则表达式完全指南
PHP提供了两种风格的正则表达式支持:PCRE(Perl Compatible Regular Expressions)和POSIX。由于POSIX已经废弃,本指南将专注于PCRE风格的正则表达式使用。
1. 基础知识
1.1 正则表达式函数
PHP中最常用的正则表达式函数:
// 查找匹配
preg_match() // 返回第一个匹配
preg_match_all() // 返回所有匹配
// 替换
preg_replace() // 替换匹配的内容
preg_replace_callback() // 使用回调函数替换
// 分割
preg_split() // 使用正则表达式分割字符串
// 过滤
preg_grep() // 返回匹配模式的数组元素
1.2 基本语法示例
<?php
// 1. 基本匹配
$text = "Hello, my phone is 123-456-7890";
// 查找第一个匹配
if (preg_match('/\d+/', $text, $matches)) {
echo "Found: " . $matches[0]; // 输出: 123
}
// 查找所有匹配
if (preg_match_all('/\d+/', $text, $matches)) {
print_r($matches[0]); // 输出: Array([0]=>123 [1]=>456 [2]=>7890)
}
// 2. 使用不同分隔符
// 使用 / 分隔符
$pattern1 = '/pattern/';
// 使用 # 分隔符
$pattern2 = '#pattern#';
// 使用 ~ 分隔符
$pattern3 = '~pattern~';
2. 模式修饰符
PHP支持多种模式修饰符,用于改变匹配行为:
<?php
$text = "Hello WORLD\nNew Line";
// i - 不区分大小写
preg_match('/hello/i', $text); // 匹配成功
// m - 多行模式
preg_match('/^New/m', $text); // 匹配成功
// s - 点号匹配所有字符(包括换行)
preg_match('/Hello.*Line/s', $text); // 匹配成功
// x - 忽略空白字符和注释
$pattern = '/
\d+ # 匹配数字
\s* # 可选的空白字符
\w+ # 匹配单词
/x';
// u - Unicode模式
preg_match('/\p{Han}/u', '你好'); // 匹配中文字符
3. 常用匹配模式
3.1 字符匹配
<?php
$text = "PHP 7.4 is awesome! Price: $99.99";
// 匹配数字
preg_match_all('/\d+/', $text, $matches);
// 匹配单词
preg_match_all('/\w+/', $text, $matches);
// 匹配空白字符
preg_match_all('/\s+/', $text, $matches);
// 自定义字符类
preg_match_all('/[aeiou]/', $text, $matches); // 匹配元音字母
3.2 数量词
<?php
$text = "PHP PHPPPProgramming";
// * - 零次或多次
preg_match('/P*/', $text);
// + - 一次或多次
preg_match('/P+/', $text);
// ? - 零次或一次
preg_match('/P?/', $text);
// {n} - 精确n次
preg_match('/P{2}/', $text);
// {n,m} - n到m次
preg_match('/P{2,4}/', $text);
4. 高级特性
4.1 分组和捕获
<?php
$text = "John Smith, Jane Doe, Bob Johnson";
// 基本分组
preg_match_all('/(\w+)\s(\w+)/', $text, $matches);
print_r($matches); // 包含完整匹配和子组
// 命名分组
preg_match_all('/(?P<first>\w+)\s(?P<last>\w+)/', $text, $matches);
print_r($matches['first']); // 访问命名组
// 非捕获组
preg_match_all('/(?:\w+)\s(\w+)/', $text, $matches);
4.2 前向查找和后向查找
<?php
$text = "Price: $100, Cost: $50";
// 正向前向查找
preg_match_all('/\d+(?=\s*dollars)/', $text, $matches);
// 负向前向查找
preg_match_all('/\d+(?!\s*dollars)/', $text, $matches);
// 正向后向查找
preg_match_all('/(?<=\$)\d+/', $text, $matches);
// 负向后向查找
preg_match_all('/(?<!\$)\d+/', $text, $matches);
5. 实用示例
5.1 数据验证
<?php
class Validator {
// 验证电子邮件
public static function validateEmail($email) {
return (bool) preg_match(
'/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/',
$email
);
}
// 验证中国手机号
public static function validatePhone($phone) {
return (bool) preg_match(
'/^1[3-9]\d{9}$/',
$phone
);
}
// 验证密码强度
public static function validatePassword($password) {
return (bool) preg_match(
'/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]{8,}$/',
$password
);
}
// 验证URL
public static function validateUrl($url) {
return (bool) preg_match(
'/^https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_\+.~#?&\/=]*)$/',
$url
);
}
}
5.2 文本处理
<?php
class TextProcessor {
// 提取URL
public static function extractUrls($text) {
preg_match_all(
'/https?:\/\/(?:[-\w.]|(?:%[\da-fA-F]{2}))+/',
$text,
$matches
);
return $matches[0];
}
// 清理HTML标签
public static function stripTags($text) {
return preg_replace('/<[^>]*>/', '', $text);
}
// 清理多余空白
public static function cleanWhitespace($text) {
return preg_replace('/\s+/', ' ', trim($text));
}
// 提取图片标签
public static function extractImages($html) {
preg_match_all('/<img[^>]+src=([\'"])?([^"\'>]+)/', $html, $matches);
return $matches[2];
}
}
6. 性能优化
6.1 正则表达式缓存
<?php
// 使用静态变量缓存编译后的正则表达式
class RegexCache {
private static $patterns = [];
public static function match($pattern, $subject) {
if (!isset(self::$patterns[$pattern])) {
// 首次使用时编译
self::$patterns[$pattern] = $pattern;
}
return preg_match(self::$patterns[$pattern], $subject);
}
}
6.2 优化建议
<?php
// 1. 使用适当的锚点
// 不好的写法
$pattern = '/\d+/';
// 好的写法
$pattern = '/^\d+$/';
// 2. 避免过度使用通配符
// 不好的写法
$pattern = '/.*foo.*/';
// 好的写法
$pattern = '/[^\/]*foo[^\/]*/';
// 3. 使用非捕获组
// 不好的写法
$pattern = '/(\d+)([a-z]+)/';
// 好的写法(当不需要捕获时)
$pattern = '/(?:\d+)(?:[a-z]+)/';
7. 错误处理
<?php
function safeRegex($pattern, $subject) {
$result = false;
try {
// 设置错误处理器
set_error_handler(function($severity, $message, $file, $line) {
throw new ErrorException($message, 0, $severity, $file, $line);
});
$result = preg_match($pattern, $subject);
restore_error_handler();
} catch (Exception $e) {
// 处理正则表达式错误
error_log("Regex error: " . $e->getMessage());
return false;
}
return $result;
}
8. 测试正则表达式
<?php
class RegexTest extends PHPUnit\Framework\TestCase {
public function testEmailValidation() {
$validator = new Validator();
$this->assertTrue($validator->validateEmail('test@example.com'));
$this->assertFalse($validator->validateEmail('invalid.email'));
$this->assertTrue($validator->validateEmail('user@domain.co.uk'));
}
public function testPhoneValidation() {
$validator = new Validator();
$this->assertTrue($validator->validatePhone('13812345678'));
$this->assertFalse($validator->validatePhone('12345678'));
}
}
总结
PHP的正则表达式实现具有以下特点:
- 完整支持PCRE语法
- 提供丰富的内置函数
- 支持Unicode
- 可以使用不同的分隔符
最佳实践:
- 选择合适的分隔符,避免过度转义
- 使用命名捕获组提高代码可读性
- 适当使用模式修饰符
- 注意性能优化
- 做好错误处理
- 编写单元测试
注意事项:
- 正则表达式可能影响性能,需要谨慎使用
- 复杂的正则表达式应该添加注释
- 考虑使用缓存机制
- 处理大文本时要注意内存使用
记住:在PHP中使用正则表达式时,应该平衡效率和可维护性。过于复杂的正则表达式往往会带来维护困难,适当拆分复杂的匹配逻辑可以提高代码的可维护性。
更多推荐
所有评论(0)