正则表达式(Regular Expression,简称regex或regexp),是一种用来匹配字符串的强大工具。它通过一套特殊的语法规则,描述字符串的模式,可以用来查找、替换、验证、提取字符串。
在PHP开发中,正则表达式是一个非常有用的工具。无论是表单验证(邮箱、手机号、URL)、字符串处理(查找替换、提取信息)、文本解析(解析日志、解析HTML),还是数据清洗,正则表达式都能大大提高效率。
但正则表达式的语法比较特殊,初学者往往觉得很难、很晦涩。其实,只要掌握了基本的语法规则,正则表达式并没有那么难。今天分享PHP正则表达式的详解,从基础到进阶,帮你掌握这个强大的工具。
PHP中的正则表达式函数
PHP提供了两套正则表达式函数:PCRE(Perl兼容正则表达式)和POSIX扩展正则表达式。POSIX已经在PHP 5.3中废弃,PHP 7中移除,所以现在都用PCRE函数。
常用的PCRE函数:
preg_match():执行一个正则匹配,返回匹配次数(0或1)pregmatchall():执行全局正则匹配,返回所有匹配结果preg_replace():执行正则替换preg_split():用正则表达式分割字符串preg_grep():返回匹配模式的数组条目preg_quote():转义正则表达式中的特殊字符
注意:PCRE正则表达式需要用分隔符包裹,常用/作为分隔符,也可以用#、~等。
正则表达式基础语法
1. 普通字符
普通字符(字母、数字、汉字等)匹配它们本身。
preg_match('/hello/', 'hello world'); // 匹配成功,返回12. 元字符
元字符是正则表达式中有特殊含义的字符,需要转义才能匹配本身。
常用元字符:
.:匹配除换行符外的任意单个字符^:匹配字符串的开头$:匹配字符串的结尾*:匹配前面的字符0次或多次+:匹配前面的字符1次或多次?:匹配前面的字符0次或1次{n}:匹配前面的字符恰好n次{n,}:匹配前面的字符至少n次{n,m}:匹配前面的字符n到m次[]:字符类,匹配方括号中的任意一个字符|:或,匹配左边或右边的表达式():分组,将括号内的表达式作为一个整体\:转义字符,转义元字符
3. 字符类
[]用来定义字符类,匹配方括号中的任意一个字符。
preg_match('/[abc]/', 'a'); // 匹配a、b、c中的任意一个
preg_match('/[a-z]/', 'm'); // 匹配a到z中的任意一个小写字母
preg_match('/[A-Z]/', 'M'); // 匹配A到Z中的任意一个大写字母
preg_match('/[0-9]/', '5'); // 匹配0到9中的任意一个数字
preg_match('/[a-zA-Z0-9]/', 'x'); // 匹配字母和数字
preg_match('/[^abc]/', 'd'); // ^在[]中表示取反,匹配不是a、b、c的字符4. 预定义字符类
正则表达式提供了一些预定义的字符类,方便使用:
\d:匹配任意数字,等价于[0-9]\D:匹配任意非数字,等价于[^0-9]\w:匹配任意字母、数字、下划线,等价于[a-zA-Z0-9_]\W:匹配任意非字母、数字、下划线\s:匹配任意空白字符(空格、制表符、换行符等)\S:匹配任意非空白字符
5. 量词
量词用来指定前面的字符匹配多少次:
*:0次或多次,等价于{0,}+:1次或多次,等价于{1,}?:0次或1次,等价于{0,1}{n}:恰好n次{n,}:至少n次{n,m}:n到m次
preg_match('/a*/', 'aaa'); // 匹配0个或多个a
preg_match('/a+/', 'aaa'); // 匹配1个或多个a
preg_match('/a?/', 'a'); // 匹配0个或1个a
preg_match('/a{3}/', 'aaa'); // 匹配恰好3个a
preg_match('/a{2,}/', 'aaa'); // 匹配至少2个a
preg_match('/a{2,4}/', 'aaa'); // 匹配2到4个a6. 贪婪与非贪婪
量词默认是贪婪的,会尽可能多地匹配。在量词后面加?,变成非贪婪,会尽可能少地匹配。
$str = '<div>hello</div><div>world</div>';
preg_match('/<div>.*<\/div>/', $str, $matches); // 贪婪,匹配整个字符串
echo $matches[0]; // <div>hello</div><div>world</div>
preg_match('/<div>.*?<\/div>/', $str, $matches); // 非贪婪,只匹配第一个
echo $matches[0]; // <div>hello</div>7. 分组和捕获
()用来分组,将括号内的表达式作为一个整体,同时捕获匹配的内容。
preg_match('/(\d{4})-(\d{2})-(\d{2})/', '2015-07-05', $matches);
echo $matches[0]; // 2015-07-05(整个匹配)
echo $matches[1]; // 2015(第一个分组)
echo $matches[2]; // 07(第二个分组)
echo $matches[3]; // 05(第三个分组)非捕获分组:(?:)只分组,不捕获。
preg_match('/(?:\d{4})-(\d{2})/', '2015-07', $matches);
echo $matches[1]; // 07(只有一个捕获分组)8. 或运算
|表示或,匹配左边或右边的表达式。
preg_match('/cat|dog/', 'I have a dog'); // 匹配cat或dog
preg_match('/(red|green|blue)/', 'The sky is blue'); // 匹配red、green或blue9. 锚点
锚点用来匹配位置,而不是字符:
^:匹配字符串开头$:匹配字符串结尾\b:匹配单词边界\B:匹配非单词边界
preg_match('/^hello/', 'hello world'); // 匹配开头的hello
preg_match('/world$/', 'hello world'); // 匹配结尾的world
preg_match('/\bcat\b/', 'the cat is black'); // 匹配单词cat,不匹配category10. 修饰符
正则表达式的分隔符后面可以加修饰符,改变匹配行为:
i:不区分大小写m:多行模式,^和$匹配每行的开头和结尾s:点号.匹配包括换行符在内的所有字符x:忽略正则表达式中的空白和注释u:UTF-8模式,正确处理多字节字符(中文)
preg_match('/hello/i', 'HELLO WORLD'); // 不区分大小写,匹配成功
preg_match('/^hello/m', "hello\nworld"); // 多行模式
preg_match('/hello.*world/s', "hello\nworld"); // 点号匹配换行符常用正则表达式示例
1. 邮箱验证
$email = 'test@example.com';
if (preg_match('/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/', $email)) {
echo "邮箱格式正确";
} else {
echo "邮箱格式错误";
}2. 手机号验证
$phone = '13812345678';
if (preg_match('/^1[3-9]\d{9}$/', $phone)) {
echo "手机号格式正确";
} else {
echo "手机号格式错误";
}3. URL验证
$url = 'http://www.example.com/path?query=1';
if (preg_match('/^https?:\/\/[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}(\/[^\s]*)?$/', $url)) {
echo "URL格式正确";
} else {
echo "URL格式错误";
}4. IP地址验证
$ip = '192.168.1.1';
if (preg_match('/^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$/', $ip)) {
echo "IP地址格式正确";
} else {
echo "IP地址格式错误";
}5. 日期验证
$date = '2015-07-05';
if (preg_match('/^(\d{4})-(\d{2})-(\d{2})$/', $date, $matches)) {
echo "年:" . $matches[1] . ",月:" . $matches[2] . ",日:" . $matches[3];
}6. 提取HTML标签内容
$html = '<div class="title">Hello World</div>';
preg_match('/<div class="title">(.*?)<\/div>/', $html, $matches);
echo $matches[1]; // Hello World7. 提取所有链接
$html = '<a href="http://example.com">链接1</a><a href="http://test.com">链接2</a>';
preg_match_all('/<a href="(.*?)">(.*?)<\/a>/', $html, $matches);
foreach ($matches[1] as $i => $url) {
echo "链接" . ($i+1) . ":" . $url . ",文字:" . $matches[2][$i] . "\n";
}8. 替换敏感词
$text = '这是一个敏感词测试,敏感词会被替换';
$badWords = ['敏感词', '测试'];
foreach ($badWords as $word) {
$text = preg_replace('/' . $word . '/', '***', $text);
}
echo $text; // 这是一个*** ***,***会被替换9. 分割字符串
$text = 'a,b,c,d,e';
$parts = preg_split('/,/', $text);
print_r($parts); // Array([0]=>a [1]=>b [2]=>c [3]=>d [4]=>e)10. 去除HTML标签
$html = '<p>Hello <b>World</b></p>';
$text = preg_replace('/<[^>]+>/', '', $html);
echo $text; // Hello World
// 也可以用strip_tags()函数正则表达式的最佳实践
- 不要过度使用正则:能用字符串函数(strpos、str_replace、substr等)解决的,就不要用正则,字符串函数更快。
- 测试正则表达式:写好正则后,一定要测试,确保匹配正确。可以用在线正则测试工具(如regex101.com)测试。
- 注意性能:复杂的正则表达式可能很慢,尤其是在处理大量数据时。尽量简化正则,避免灾难性回溯。
- 使用pregquote转义:如果正则表达式中包含用户输入,一定要用pregquote()转义特殊字符。
- 添加注释:复杂的正则表达式,可以用
x修饰符添加注释,提高可读性。 - 使用UTF-8模式:处理中文时,一定要加
u修饰符,否则可能匹配不正确。 - 避免贪婪匹配:默认的贪婪匹配可能导致匹配过多,用
?改成非贪婪。
常见错误
- 忘记分隔符:PCRE正则必须用分隔符包裹,如
/pattern/。 - 没有转义特殊字符:
.、*、+等元字符需要转义才能匹配本身。 - 贪婪匹配导致匹配过多:用
?改成非贪婪。 - 没有加锚点:验证字符串格式时,一定要加
^和$,否则可能部分匹配。 - 中文匹配问题:处理中文时加
u修饰符。 - pregmatch只匹配一次:需要匹配所有结果时,用pregmatch_all。
总结
正则表达式是PHP开发中非常有用的工具,掌握它能大大提高字符串处理的效率。
核心要点:
- 基础语法:普通字符、元字符、字符类、预定义字符类、量词、分组、或运算、锚点、修饰符
- 常用函数:pregmatch、pregmatchall、pregreplace、pregsplit、preggrep、preg_quote
- 常用正则:邮箱、手机号、URL、IP、日期、HTML标签提取、敏感词替换
- 最佳实践:不要过度使用、测试、注意性能、转义用户输入、添加注释、UTF-8模式
- 常见错误:忘记分隔符、没有转义、贪婪匹配、没有锚点、中文匹配问题
正则表达式虽然看起来复杂,但只要掌握了基本语法,多练习,多使用,就能熟练掌握。希望这篇文章能帮你掌握PHP正则表达式。
评论(0)
暂无评论,快来抢沙发~
评论功能仅对会员开放,请先登录
登录