preg_match 的用法

本文通过一个简单的实例详细介绍了PHP中preg_match函数的使用方法,并解释了如何通过正则表达式匹配字符串,以及如何从匹配结果中获取所需的部分。

大家一看到preg_match肯定会头痛的。。。其实没什么,下面我就尽力给还不明白的兄弟们争取讲明白了:
在这里我就不解释preg_match的说明了,朋友们可以通过php手册查看..先来个简单点的:

preg_match("/^(http:////)?([^//]+)/i",
"http://www.php.net/index.html", $matches);
$host = $matches[2];
// 从主机名中取得后面两段
preg_match("/[^/.//]+/.[^/.//]+$/", $host, $matches);
echo "domain name is: {$matches[0]}/n";

这是手册里的例子。多数人对preg_match犯晕都出在正则上,以后我也会介绍正则。先看这个例子,
preg_match($pattern,$string,$matcher)其中$pattern对应的就是”/^(http:////)?([^//]+)/i
$str 是http://www.php.net/index.html.$match是匹配到的结果。按照手册上的意思:
如果提供了 matches,则其会被搜索的结果所填充。$matches[0] 将包含与整个模式匹配的文本,$matches[1] 将包含与第一个捕获的括号中的子模式所匹配的文本,以此类推。
这是什么意思呢?第一句就不用解释了,$matches[0] 将包含与整个模式匹配的文本。
咱们用pring_r打印出来第一个$matches:
Array ( [0] => http://www.php.net [1] => http:// [2] => www.php.net )
这回明白了吧。。$matches[0] 将包含与整个模式匹配的文本,$matches[1] 将包含与第一个捕获的括号中的子模式所匹配的文本。在正则中,()代表模式:匹配 pattern 并获取这一匹配。所获取的匹配可以从产生的 Matches 集合得到,在VBScript 中使用 SubMatches 集合,在JScript 中则使用 $0…$9 属性。就是说数组中下标为1的值就是正则中/^(http:////)?([^//]+)/i第一个()里的值!数组下标2的值以此类推

<think>我们正在讨论`!preg_match()`的使用,这实际上是`preg_match()`的否定形式。在PHP中,`preg_match()`返回匹配的次数(0或1,因为它在第一次匹配后停止),所以`!preg_match()`通常用于检查是否没有匹配。 ### 一、`!preg_match()`的常见用法 在条件判断中,我们经常用`!preg_match()`来检查字符串中是否不存在某种模式。 #### 示例1:验证输入是否不包含特殊字符 ```php $username = $_POST['username']; // 要求用户名只包含字母和数字 if (!preg_match('/^[a-zA-Z0-9]+$/', $username)) { echo "用户名只能包含字母和数字!"; } ``` #### 示例2:检查是否不存在非法关键词 ```php $comment = $_POST['comment']; $forbiddenWords = array('spam', 'advertise', 'http://'); $pattern = '/'.implode('|', array_map('preg_quote', $forbiddenWords)).'/i'; if (!preg_match($pattern, $comment)) { // 没有匹配到禁用词,允许提交 save_comment($comment); } else { echo "评论包含禁用词!"; } ``` ### 二、常见问题与陷阱 1. **返回值判断错误** - 问题:混淆`preg_match()`返回的`0`(无匹配)和`false`(错误) - 错误示例: ```php // 错误:当正则表达式有语法错误时,preg_match返回false,!false为true,导致误判 if (!preg_match('/invalid regex(/', $input)) { // 这里可能因为正则错误而进入,并非真正的无匹配 } ``` - 正确做法:先检查错误 ```php $result = preg_match($pattern, $subject); if ($result === false) { // 处理正则错误 } elseif ($result === 0) { // 无匹配 } else { // 有匹配 } ``` 2. **多行匹配问题** - 问题:默认情况下,正则表达式将字符串视为单行,`^`和`$`只匹配整个字符串的开始和结束 - 解决方案:使用`m`修饰符启用多行模式 ```php // 检查字符串中是否没有以"end"开头的行 if (!preg_match('/^end/m', $text)) { echo "没有以'end'开头的行"; } ``` 3. **Unicode字符匹配** - 问题:未使用`u`修饰符导致中文字符等匹配失败 - 错误示例: ```php // 试图匹配中文字符,但未加u修饰符 if (!preg_match('/[\x{4e00}-\x{9fa5}]/', $text)) { // 可能错误地认为没有中文字符 } ``` - 正确做法: ```php if (!preg_match('/[\x{4e00}-\x{9fa5}]/u', $text)) { // 正确匹配Unicode } ``` 4. **性能问题** - 问题:复杂正则导致超时 - 优化:避免过度回溯,使用原子组、占有量词等 ```php // 低效:.*可能引起大量回溯 if (!preg_match('/<script>.*<\/script>/s', $html)) { ... } // 改进:使用非贪婪匹配 if (!preg_match('/<script>.*?<\/script>/s', $html)) { ... } ``` ### 三、最佳实践 1. **始终检查正则错误** 在关键逻辑中,检查`preg_match()`返回`false`的情况: ```php $pattern = '/[a-z'; if (($result = preg_match($pattern, $subject)) === false) { $error = preg_last_error_msg(); throw new Exception("正则错误: $error"); } ``` 2. **使用命名捕获组提高可读性**(PHP 7.0+) ```php if (!preg_match('/^(?<name>[a-z]+) (?<age>\d+)$/i', $input, $matches)) { echo "格式不匹配"; } else { // 即使匹配失败,$matches也可能有部分数据,但这里不会进入 } ``` 3. **调试技巧** 当`!preg_match()`表现不符合预期时: - 输出正则表达式和待匹配字符串进行验证 - 使用在线工具(如regex101.com)测试正则 - 开启`preg_last_error()`检查 ### 四、完整示例:表单验证 ```php function validate_email($email) { // 正则来自PHP官方文档 $pattern = '/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/'; return preg_match($pattern, $email) === 1; } $email = 'user@example.com'; if (!validate_email($email)) { echo "邮箱格式无效"; } else { echo "邮箱有效"; } ``` ### 五、总结 - `!preg_match()` 用于检测字符串中**不存在**正则模式匹配的内容 - 必须处理可能返回的`false`(正则错误) - 注意修饰符(如`s`, `m`, `u`)对匹配行为的影响 - 复杂正则需考虑性能问题 §§相关问题§§ 1. 如何用`preg_match_all`实现全局匹配? 2. `preg_replace`和`preg_filter`有什么区别? 3. 正则表达式中`(?=)`和`(?!)`的作用是什么? 4. 如何避免正则表达式中的回溯爆炸问题?</think>### PHP `!preg_match()` 用法详解与常见问题 `!preg_match()` 是 PHP 中**正则表达式匹配的否定判断**,常用于验证字符串**不符合**特定模式的情况。其核心逻辑是将 `preg_match()` 的返回值取反: - 当 `preg_match()` 返回 `0`(无匹配)时,`!preg_match()` 返回 `true` - 当 `preg_match()` 返回 `1`(有匹配)时,`!preg_match()` 返回 `false` #### 一、基本语法结构 ```php if (!preg_match($pattern, $subject)) { // 当字符串不匹配模式时执行的代码 } ``` #### 二、典型应用场景 1. **输入验证(黑名单模式)** ```php $username = "admin#"; // 验证用户名不含特殊字符 if (!preg_match('/^[a-zA-Z0-9_]+$/', $username)) { echo "用户名只能包含字母、数字和下划线"; } ``` 2. **安全过滤(防注入攻击)** ```php $input = $_POST['search']; // 检测是否包含SQL注入特征 if (!preg_match('/\b(UNION|SELECT|INSERT\s+INTO|DROP\s+TABLE)\b/i', $input)) { // 安全处理逻辑 } ``` 3. **格式排除(拒绝特定格式)** ```php $filename = "backup.tar.gz"; // 拒绝压缩文件上传 if (!preg_match('/\.(zip|rar|gz|tar)$/i', $filename)) { // 允许上传非压缩文件 } ``` #### 三、常见问题与解决方案 1. **返回值误判问题** - **问题**:混淆 `0`(无匹配)和 `false`(错误) - **解决方案**:严格检查返回值类型 ```php $result = preg_match($pattern, $subject); if ($result === false) { // 正则错误处理 } elseif ($result === 0) { // 无匹配逻辑 } ``` 2. **正则表达式语法错误** - **问题**:无效正则导致返回 `false`,`!false` 为 `true` - **调试方法**: ```php if (@!preg_match('/invalid(regex/', $str)) { $error = preg_last_error(); error_log("正则错误: ".preg_last_error_msg()); } ``` 3. **多行文本处理异常** - **问题**:默认单行模式导致 `^` 和 `$` 行为不符合预期 - **解决方案**:使用 `m` 修饰符 ```php // 检测文本中不存在以"error:"开头的行 if (!preg_match('/^error:/m', $logContent)) { echo "日志无错误记录"; } ``` 4. **UTF-8 字符匹配问题** - **问题**:未使用 `u` 修饰符导致中文匹配失败 - **正确用法**: ```php // 验证不含中文 if (!preg_match('/[\x{4e00}-\x{9fa5}]/u', $text)) { echo "文本不含中文字符"; } ``` #### 四、性能优化技巧 1. **避免回溯爆炸** ```php // 低效写法(易引发回溯) !preg_match('/<div>.*<\/div>/s', $html); // 优化方案(使用非贪婪和明确边界) !preg_match('/<div>.*?<\/div>/s', $html); ``` 2. **设置回溯限制** ```php ini_set('pcre.backtrack_limit', 10000); // 防止超长文本匹配超时 ``` #### 五、完整示例:邮箱白名单验证 ```php $email = "user@example.com"; $allowedDomains = ['gmail.com', 'outlook.com', 'company.com']; $pattern = '/@('.implode('|', array_map('preg_quote', $allowedDomains)).')$/i'; if (!preg_match($pattern, $email)) { echo "仅允许以下邮箱: ".implode(', ', $allowedDomains); } else { echo "邮箱验证通过"; } ``` #### 六、调试建议 1. 使用在线工具(如 [regex101.com](https://regex101.com/))预先测试正则 2. 错误捕获: ```php set_error_handler(function($errno, $errstr) { if (str_contains($errstr, 'preg_match')) { die("正则错误: $errstr"); } }); ``` > **关键点**:`!preg_match()` 本质是 `preg_match() === 0` 的简写形式,但需注意区分 `0`(无匹配)和 `false`(错误)两种状态[^1][^4]。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值