首页 / PHP 入门教程 / PHP 正则表达式

PHP 入门教程

PHP 正则表达式

本教程共 65 篇 · 第 34 篇 · 更新于 2026-07-24 · 约 5 分钟阅读

PHPPHP8正则表达式preg_matchpreg_replace匹配

34. PHP 正则表达式

本节目标:掌握 preg_matchpreg_replace 的基础用法,了解常用元字符、分组和命名捕获,能写出常见的匹配模式。

正则表达式(Regular Expression)是文本匹配的利器。验证手机号、提取链接、替换敏感词,都离不开它。

34.1 基础函数

preg_match 匹配一次

<?php
$text = "我的邮箱是 test@example.com";

if (preg_match('/\w+@\w+\.\w+/', $text, $matches)) {
    echo "匹配到:" . $matches[0]; // test@example.com
}

preg_match_all 匹配所有

<?php
$html = "<a href='http://a.com'>A</a> <a href='https://b.com'>B</a>";

preg_match_all('/href=[\'"](.+?)[\'"]/', $html, $matches);
print_r($matches[1]);
// Array ( [0] => http://a.com [1] => https://b.com )

preg_replace 替换

<?php
$text = "电话:138-1234-5678,备用:139-8765-4321";

// 把手机号中间四位隐藏
$result = preg_replace('/(\d{3})-\d{4}-(\d{4})/', '$1-****-$2', $text);
echo $result; // 电话:138-****-5678,备用:139-****-4321

34.2 常用元字符

元字符含义
.任意单个字符(除换行)
\d数字 [0-9]
\w字母、数字、下划线 [a-zA-Z0-9_]
\s空白字符
^字符串开头
$字符串结尾
*前面字符出现 0 次或多次
+前面字符出现 1 次或多次
?前面字符出现 0 次或 1 次
{n,m}前面字符出现 n 到 m 次
Note

正则表达式放在 /pattern/ 的定界符中,PHP 也支持 #pattern#~pattern~ 等定界符。

34.3 实用匹配示例

验证手机号(中国大陆)

<?php
$phone = "13812345678";
$pattern = '/^1[3-9]\d{9}$/';

if (preg_match($pattern, $phone)) {
    echo "手机号格式正确";
}

验证邮箱

<?php
$email = "user.name+tag@example.co.uk";
$pattern = '/^[\w.+-]+@[\w.-]+\.\w+$/';

if (preg_match($pattern, $email)) {
    echo "邮箱格式基本正确";
}
Tip

完整邮箱正则极其复杂。生产环境建议用 filter_var($email, FILTER_VALIDATE_EMAIL),更可靠。

提取 HTML 标签内容

<?php
$html = "<h1>标题</h1><p>段落内容</p>";

preg_match_all('/<(\w+)>(.+?)<\/\1>/', $html, $matches, PREG_SET_ORDER);

foreach ($matches as $match) {
    echo "标签:{$match[1]},内容:{$match[2]}\n";
}
// 标签:h1,内容:标题
// 标签:p,内容:段落内容

34.4 分组与捕获

用小括号 () 创建捕获组,用 $1$2\1\2 引用:

<?php
$date = "2026-07-24";

// 提取年、月、日
preg_match('/(\d{4})-(\d{2})-(\d{2})/', $date, $m);
echo "年:{$m[1]},月:{$m[2]},日:{$m[3]}";

// 格式转换:2026-07-24 -> 24/07/2026
$newDate = preg_replace('/(\d{4})-(\d{2})-(\d{2})/', '$3/$2/$1', $date);
echo $newDate; // 24/07/2026

非捕获分组

不需要捕获时用 (?:...) 提升性能:

<?php
$pattern = '/(?:https?:\/\/)?(www\.\w+\.\w+)/';
preg_match($pattern, "https://www.example.com", $m);
echo $m[1]; // www.example.com

34.5 命名捕获(PHP 7+ 推荐)

给捕获组起名字,结果更易读:

<?php
$date = "2026-07-24";

preg_match(
    '/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/',
    $date,
    $matches
);

echo $matches["year"];   // 2026
echo $matches["month"];  // 07
echo $matches["day"];    // 24
Tip

命名捕获让代码自文档化,维护时不用数 $1$2 到底对应什么。

34.6 修饰符

放在定界符后面,控制匹配行为:

修饰符作用
i忽略大小写
m多行模式,^$ 匹配每行开头结尾
s单行模式,. 匹配换行符
uUTF-8 模式,正确处理中文
<?php
// 忽略大小写
preg_match('/php/i', "PHP 是最好的语言"); // 匹配成功

// 正确处理中文(必须加 u 修饰符)
preg_match('/^[\x{4e00}-\x{9fa5}]+$/u', "张三李四"); // 匹配纯中文

34.7 常见错误提醒

  • 定界符冲突:正则里有 / 时,定界符改用 #~
  • 忘记加 u 修饰符:匹配中文时结果异常
  • 贪婪匹配过多.* 会匹配尽可能多,改用 .*? 非贪婪匹配
  • 未转义特殊字符.*? 等要用 \.\* 转义

来源:参考了 runoob「PHP PCRE」、w3cschool「PHP 正则表达式」等,改写后所得。