PHP 正则表达式(PCRE):从入门到实战应用
在处理文本数据时,你是否经常遇到需要从一段字符串中提取特定信息的场景?比如验证邮箱格式、过滤敏感词、解析日志文件,或是从网页中抓取标题?这些任务如果用传统的字符串匹配方法,代码会变得冗长且难以维护。而 PHP 正则表达式(PCRE) 正是为这类问题量身打造的利器。
它不是简单地“查找”字符串,而是通过定义一套规则(模式),让程序“理解”你想找的内容。你可以把它想象成一个智能搜索过滤器,不仅能找“有没有”,还能告诉你“是什么”“在哪”“有多少”。
本文将带你系统掌握 PHP 正则表达式(PCRE) 的核心语法与实战技巧,无论你是刚接触 PHP 的新手,还是有一定经验的开发者,都能从中获得实用价值。
什么是 PHP 正则表达式(PCRE)
PCRE 是“Perl Compatible Regular Expressions”的缩写,意为“与 Perl 兼容的正则表达式”。PHP 从 5.3 版本起,内置了 PCRE 扩展,成为处理复杂文本匹配的首选方案。
与传统字符串函数(如 strpos、substr)相比,正则表达式更强大、更灵活。它允许你用“模式”描述文本结构,从而实现精准匹配。
举个例子:
<?php
$text = "我的邮箱是 john@example.com,电话是 138-1234-5678。";
// 用正则匹配邮箱格式
if (preg_match('/^\w+@\w+\.\w+$/', $text, $matches)) {
echo "找到了邮箱:{$matches[0]}\n"; // 输出:找到了邮箱:john@example.com
}
这段代码中,/^\w+@\w+\.\w+$/ 就是一个正则表达式模式。它描述了“以字母数字下划线开头,中间有 @,后面是域名和顶级域名”的邮箱结构。
注释:
preg_match是 PHP 中用于执行正则匹配的核心函数。/.../是模式的分隔符,^表示字符串开头,\w匹配字母、数字、下划线,@是字面量字符,\.表示点号本身(因为点号在正则中有特殊含义),$表示字符串结尾。
常用的元字符与量词
正则表达式的核心在于“元字符”——这些字符本身没有字面意义,而是赋予特殊含义。理解它们是掌握 PCRE 的第一步。
常见元字符
| 元字符 | 含义 | 示例 |
|---|---|---|
. |
匹配任意单个字符(换行符除外) | a.c 可匹配 "abc"、"a1c" |
^ |
匹配字符串开头 | ^Hello 匹配以 Hello 开头的字符串 |
$ |
匹配字符串结尾 | world$ 匹配以 world 结尾的字符串 |
* |
匹配前一个字符 0 次或多次 | a* 可匹配 ""、"a"、"aa" |
+ |
匹配前一个字符 1 次或多次 | a+ 不能匹配 "",但能匹配 "a"、"aa" |
? |
匹配前一个字符 0 次或 1 次 | a? 可匹配 "" 或 "a" |
\d |
匹配数字 0-9 | \d{3} 匹配三个连续数字 |
\w |
匹配字母、数字、下划线 | \w+ 匹配一个或多个单词字符 |
\s |
匹配空白字符(空格、制表符、换行符) | \s+ 匹配一个或多个空白 |
量词使用示例
<?php
$phone = "电话:138-1234-5678";
// 匹配 3 位数字 + 连字符 + 4 位数字 + 连字符 + 4 位数字
if (preg_match('/\d{3}-\d{4}-\d{4}/', $phone, $matches)) {
echo "找到有效手机号:{$matches[0]}\n"; // 输出:找到有效手机号:138-1234-5678
}
注释:
\d{3}表示匹配恰好 3 个数字,{4}同理。这种{n}写法是量词的简写形式,可以精确控制重复次数。
字符类与分组
当你要匹配的字符范围较广时,字符类(Character Classes)就派上用场了。
字符类
| 写法 | 含义 |
|---|---|
[abc] |
匹配 a、b 或 c 中的任意一个 |
[a-z] |
匹配 a 到 z 之间的任意小写字母 |
[0-9] |
匹配 0 到 9 之间的任意数字 |
[^abc] |
匹配非 a、非 b、非 c 的字符(取反) |
分组与捕获
分组用括号 ( ) 表示,它不仅能将多个字符组合成一个单元,还能“记住”匹配的内容,供后续使用。
<?php
$text = "姓名:张三,年龄:25岁,城市:北京";
// 匹配姓名、年龄、城市三部分
if (preg_match('/姓名:(.*?)[,,]年龄:(\d+)岁[,,]城市:(.*?)$/', $text, $matches)) {
echo "姓名:{$matches[1]}\n"; // 张三
echo "年龄:{$matches[2]}\n"; // 25
echo "城市:{$matches[3]}\n"; // 北京
}
注释:
(...)是捕获组,每个组的内容会被存入$matches数组中。.*?是非贪婪匹配,避免一次性吃掉所有内容。[,,]表示中文逗号或英文逗号,确保兼容多种分隔符。
常用 PHP 正则函数解析
PHP 提供了多个函数来支持正则操作,掌握它们能让你高效完成任务。
preg_match:匹配一次
用于判断是否匹配成功,返回 1(成功)、0(失败)或 false(错误)。
<?php
$email = "user@domain.com";
if (preg_match('/^\w+@\w+\.\w+$/', $email)) {
echo "邮箱格式正确\n";
} else {
echo "邮箱格式错误\n";
}
preg_match_all:全局匹配
找出所有匹配项,适合提取多个结果。
<?php
$text = "电话:138-1234-5678,另一个:159-8765-4321";
// 提取所有手机号
preg_match_all('/\d{3}-\d{4}-\d{4}/', $text, $matches);
foreach ($matches[0] as $phone) {
echo "手机号:{$phone}\n";
}
preg_replace:替换匹配内容
用新字符串替换匹配到的部分。
<?php
$html = "<p>欢迎访问我们的网站</p><a href='/about'>关于我们</a>";
// 将所有 a 标签替换为链接文本
$result = preg_replace('/<a\s+[^>]*>(.*?)<\/a>/', '[$1]', $html);
echo $result; // 输出:[欢迎访问我们的网站][关于我们]
注释:
<a\s+[^>]*>匹配 a 标签及其属性,[^>]*表示非 > 的任意字符,\s+表示一个或多个空白符。
实战案例:邮箱与手机号验证
我们来做一个完整的验证功能,展示 PHP 正则表达式(PCRE) 如何在实际项目中应用。
<?php
function validateEmail($email) {
// 常见邮箱格式:用户名@域名.后缀
$pattern = '/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/';
return preg_match($pattern, $email);
}
function validatePhone($phone) {
// 支持 11 位手机号,可带连字符或空格
$pattern = '/^1[3-9]\d{9}$|^\d{3}[-\s]?\d{4}[-\s]?\d{4}$/';
return preg_match($pattern, $phone);
}
// 测试数据
$testEmails = [
'user@example.com',
'invalid.email',
'test@sub.domain.co.uk'
];
$testPhones = [
'13812345678',
'138-1234-5678',
'138 1234 5678',
'12345678901'
];
echo "=== 邮箱验证 ===\n";
foreach ($testEmails as $email) {
echo "{$email} -> " . (validateEmail($email) ? '有效' : '无效') . "\n";
}
echo "\n=== 手机号验证 ===\n";
foreach ($testPhones as $phone) {
echo "{$phone} -> " . (validatePhone($phone) ? '有效' : '无效') . "\n";
}
注释:
[a-zA-Z0-9._%+-]+表示邮箱用户名部分可包含字母、数字、点、下划线、百分号、加号、减号。{2,}表示至少两个字符,确保顶级域名如 .com、.org 有效。^1[3-9]\d{9}$是中国大陆手机号的标准格式。
常见陷阱与最佳实践
在使用 PHP 正则表达式(PCRE) 时,有几个容易踩坑的地方需要特别注意:
- 忘记转义特殊字符:如
.、*、+、?等在正则中有特殊含义,若要匹配字面量,必须加反斜杠\.。 - 贪婪 vs 非贪婪:默认
*、+是贪婪的,会尽可能多地匹配。如需最小匹配,使用*?、+?。 - 性能问题:过于复杂的正则可能导致性能下降,尤其在处理大文本时。
- 编码问题:确保文本是 UTF-8 编码,否则中文字符可能匹配失败。可配合
u修饰符使用:/pattern/u。
<?php
// 正确:匹配中文字符
$text = "你好,世界";
if (preg_match('/^[\p{Han}]+$/u', $text)) {
echo "包含中文字符\n";
}
注释:
\p{Han}是 Unicode 中文字符类别,u修饰符启用 UTF-8 模式,确保中文能被正确识别。
总结
PHP 正则表达式(PCRE) 是处理文本的强大工具,它不仅能简化字符串操作,还能提升代码的可读性和维护性。通过掌握元字符、量词、分组、字符类等核心概念,你可以在项目中灵活应对各种文本处理需求。
从邮箱验证到日志解析,从数据清洗到内容提取,正则表达式都能成为你的得力助手。虽然初学时可能觉得复杂,但只要多写多练,你会发现它其实非常“有逻辑”且“有美感”。
别再用繁琐的字符串处理了,让 PHP 正则表达式(PCRE) 帮你写出更优雅、更高效的代码。