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比.更高效)。

四、下一步学习建议

  1. 进阶语法:学习正向预查((?=...))、反向预查((?<=...)),实现更复杂匹配(如 “匹配不含某字符的字符串”);
  1. 工具辅助:用在线工具测试正则(如Regex101,支持 PHP 语法);
  1. 实战场景:尝试用正则处理 JSON 格式校验、HTML 标签清理、日志内容提取等实际需求。
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐