PHP 正则表达式功能代码实现指南
PHP 正则表达式功能代码实现指南
正则表达式(Regex)是处理字符串的强大工具,在 PHP 中常用于数据验证、内容提取、格式替换等场景。本文将从基础语法到实战案例,逐步讲解 PHP 正则表达式的使用方法,所有示例均提供可直接运行的代码。
一、PHP 正则表达式基础
1. 正则表达式的 “PHP 风格”
PHP 中使用正则表达式需加定界符(包裹正则内容),常用定界符为 /(若正则含/,可改用#或~避免转义),格式如下:
$pattern = '/正则表达式/修饰符'; // 标准格式
$pattern = '#正则表达式#修饰符'; // 当正则含/时,如匹配URL:#https?://#
2. 核心修饰符(常用)
| 修饰符 | 作用 |
| i | 不区分大小写匹配 |
| g | 全局匹配(仅部分函数生效,如 preg_replace) |
| m | 多行匹配(^ 匹配行开头,$ 匹配行结尾) |
| s | 单行匹配(. 匹配所有字符,包括换行符 \n) |
3. PHP 正则核心函数(必学)
| 函数名 | 功能 | 返回值 | 适用场景 |
| preg_match() | 匹配 1 次(首次匹配) | 成功返回 1,失败返回 0,错误返回 false | 数据验证(如邮箱) |
| preg_match_all() | 全局匹配(所有结果) | 成功返回匹配次数,失败返回 0/false | 内容提取(如抓链接) |
| preg_replace() | 正则替换 | 返回替换后的字符串 | 格式统一、敏感词过滤 |
| preg_split() | 按正则分割字符串 | 返回分割后的数组 | 复杂分割(如多符号分割) |
二、场景化代码实现(含详解)
所有示例代码可直接放在 PHP 环境根目录(如D:\xampp\htdocs),通过http://localhost/文件名.php运行。
场景 1:数据验证(最常用)
需求 1.1:验证邮箱格式
正则逻辑:
- 用户名:允许字母、数字、下划线、点、减号([a-zA-Z0-9_-])
- 域名:@后需有域名(如@qq.com,[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})
<?php
// 邮箱验证函数
function validateEmail($email) {
// 正则表达式:定界符/,修饰符i(不区分大小写) // 测试代码 来源:NvCaG.n1p.pro
$pattern = '/^[a-zA-Z0-9_-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/i';
// preg_match:匹配成功返回1,失败返回0
return preg_match($pattern, $email) ? '邮箱格式正确' : '邮箱格式错误';
}
// 测试案例测试代码 来源:9cB.c8x.biz
$testEmails = [
'test@qq.com', // 正确
'Test-123@gmail.com', // 正确(含大写、减号)
'test@.com', // 错误(域名缺失)
'test@qq' // 错误(无后缀)
];
foreach ($testEmails as $email) {
echo "邮箱:{$email} → " . validateEmail($email) . "<br>";
}
?>
运行结果:
邮箱:test@qq.com → 邮箱格式正确
邮箱:Test-123@gmail.com → 邮箱格式正确
邮箱:test@.com → 邮箱格式错误
邮箱:test@qq → 邮箱格式错误
需求 1.2:验证手机号(国内 11 位)
正则逻辑:
- 开头为 1,第二位为 3/4/5/7/8/9,后续 9 位为数字(^1[345789]\d{9}$)
<?php
// 手机号验证函数
function validatePhone($phone) {
$pattern = '/^1[345789]\d{9}$/'; // 无修饰符(需严格匹配数字和长度)
return preg_match($pattern, $phone) ? "手机号{$phone}有效" : "手机号{$phone}无效";
}
// 测试案例 测试代码 来源:wTxOK.th7.pro
$testPhones = ['13812345678', '19987654321', '12345678901', '1381234567'];
foreach ($testPhones as $phone) {
echo validatePhone($phone) . "<br>";
}
?>
运行结果:
手机号13812345678有效
手机号19987654321有效
手机号12345678901无效(第二位是2,不符合规则)
手机号1381234567无效(仅10位)
场景 2:内容提取(从字符串中抓关键信息)
需求 2.1:提取 HTML 中的所有链接()
正则逻辑:
- 匹配<a href="开头,捕获双引号内的 URL(用()定义捕获组)
- 修饰符s:让.匹配换行符(HTML 可能跨行)
<?php
// 待提取的HTML内容
$html = '
<div>
<a href="https://www.baidu.com">百度</a>
<a href="https://www.php.net" class="link">PHP官网</a>
<p>非链接内容</p>
<a href="https://laravel.com">Laravel框架</a>
</div>
';
// 正则表达式:()表示捕获组,提取href的值
$pattern = '/<a\s+href="([^"]+)"/is'; // i:不区分<a/A,s:匹配换行
// preg_match_all:全局匹配,结果存入$matches
preg_match_all($pattern, $html, $matches);
// $matches[0]:完整匹配结果(如<a href="https://...)
// $matches[1]:捕获组结果(仅URL)
echo "提取到的链接:<br>";
foreach ($matches[1] as $link) {
echo "- {$link}<br>";
}
?>
运行结果:
提取到的链接:
- https://www.baidu.com
- https://www.php.net
- https://laravel.com
需求 2.2:提取字符串中的所有数字
正则逻辑:\d+匹配 1 个及以上数字,修饰符g全局匹配。
<?php
$str = '订单编号:NO12345,金额:99.9元,数量:5件';
// 正则:\d+匹配数字,\.?匹配可选的小数点(如需匹配小数)
$pattern = '/\d+\.?\d*/g'; // \.?:可选小数点,\d*:可选后续数字
// 提取所有数字(含小数)
preg_match_all($pattern, $str, $matches);
echo "提取到的数字:<br>";
print_r($matches[0]); // 输出:Array ( [0] => 12345 [1] => 99.9 [2] => 5 )
?>
场景 3:字符串替换(格式统一 / 过滤)
需求 3.1:敏感词过滤(替换为 *)
正则逻辑:用|分隔多个敏感词,修饰符i不区分大小写,g全局替换。
<?php
$content = '这个垃圾产品真差,简直是废物!';
$sensitiveWords = ['垃圾', '废物']; // 敏感词库
// 正则:implode('|', $words)将数组转为“词1|词2”
$pattern = '/'.implode('|', $sensitiveWords).'/ig';
// preg_replace:将敏感词替换为***
$filteredContent = preg_replace($pattern, '***', $content);
echo "原内容:{$content}<br>";
echo "过滤后:{$filteredContent}";
?>
运行结果:
原内容:这个垃圾产品真差,简直是废物!
过滤后:这个***产品真差,简直是***!
需求 3.2:日期格式统一(2025-10-05 → 10/05/2025)
正则逻辑:用捕获组分别匹配年、月、日,替换时调整顺序。
<?php
$dateStr = '今天是2025-10-05,昨天是2025-10-04';
// 正则:(\d{4})匹配年,(\d{2})匹配月,(\d{2})匹配日
$pattern = '/(\d{4})-(\d{2})-(\d{2})/g';
// 替换:$2=月,$3=日,$1=年(捕获组按顺序$1-$n)
$formattedDate = preg_replace($pattern, '$2/$3/$1', $dateStr);
echo "原日期:{$dateStr}<br>";
echo "格式化后:{$formattedDate}";
?>
运行结果:
原日期:今天是2025-10-05,昨天是2025-10-04
格式化后:今天是10/05/2025,昨天是10/04/2025
三、常见问题与优化技巧
1. 避免 “贪婪匹配” 陷阱
正则默认贪婪匹配(尽可能多匹配),如需 “非贪婪”(尽可能少匹配),在量词后加?:
<?php
$str = '<div>内容1</div><div>内容2</div>';
// 贪婪匹配:会匹配整个字符串(从第一个<div>到最后一个</div>)
$greedyPattern = '/<div>.*<\/div>/';
preg_match($greedyPattern, $str, $greedyMatch);
echo "贪婪匹配:{$greedyMatch[0]}<br>"; // 输出:<div>内容1</div><div>内容2</div>
// 非贪婪匹配:加?,匹配到第一个</div>就停止
$lazyPattern = '/<div>.*?<\/div>/';
preg_match($lazyPattern, $str, $lazyMatch);
echo "非贪婪匹配:{$lazyMatch[0]}"; // 输出:<div>内容1</div>
?>
2. 定界符转义问题
若正则含定界符(如/),需用\转义或换用其他定界符:
// 错误:正则中的/未转义,与定界符冲突
$badPattern = '/https://www.php.net/';
// 正确1:转义/
$goodPattern1 = '/https:\/\/www.php.net/';
// 正确2:换用#作为定界符,无需转义
$goodPattern2 = '#https://www.php.net#';
3. 性能优化
- 复杂正则加u修饰符(支持 UTF-8,避免中文乱码);
- 频繁使用的正则可提前编译(用preg_match时自动缓存,无需手动处理);
- 避免过度使用.(如匹配数字用\d比.更高效)。
四、下一步学习建议
- 进阶语法:学习正向预查((?=...))、反向预查((?<=...)),实现更复杂匹配(如 “匹配不含某字符的字符串”);
- 工具辅助:用在线工具测试正则(如Regex101,支持 PHP 语法);
- 实战场景:尝试用正则处理 JSON 格式校验、HTML 标签清理、日志内容提取等实际需求。
更多推荐



所有评论(0)