本文目录导读:

在 PHP 中,默认的正则匹配是贪婪匹配(尽可能多地匹配字符),要关闭贪婪匹配,可以使用以下几种方法:
使用非贪婪量词 (最常用)
在量词(、、)后面添加 ,使其变为非贪婪匹配。
$str = "<div>内容1</div><div>内容2</div>";
// 贪婪匹配(默认)
preg_match('/<div>(.*)<\/div>/', $str, $matches);
print_r($matches[1]); // 输出: 内容1</div><div>内容2
// 非贪婪匹配
preg_match('/<div>(.*?)<\/div>/', $str, $matches);
print_r($matches[1]); // 输出: 内容1
常用的非贪婪量词
// 贪婪的 * 改为非贪婪
*? // 匹配0次或多次,但尽可能少
// 贪婪的 + 改为非贪婪
+? // 匹配1次或多次,但尽可能少
// 贪婪的 ? 改为非贪婪
?? // 匹配0次或1次,但尽可能少
// 贪婪的 {n,m} 改为非贪婪
{n,m}? // 匹配n到m次,但尽可能少
完整示例
// 示例1:匹配HTML标签内容
$html = "<p>第一段</p><p>第二段</p>";
// 贪婪匹配
preg_match_all('/<p>(.*)<\/p>/', $html, $greedy);
print_r($greedy[1]);
// Array ( [0] => 第一段</p><p>第二段 )
// 非贪婪匹配
preg_match_all('/<p>(.*?)<\/p>/', $html, $nonGreedy);
print_r($nonGreedy[1]);
// Array ( [0] => 第一段 [1] => 第二段 )
// 示例2:匹配URL参数
$url = "?name=john&age=25&city=beijing";
// 贪婪匹配
preg_match('/name=(.*)&/', $url, $greedy);
echo $greedy[1]; // 输出: john&age=25&city
// 非贪婪匹配
preg_match('/name=(.*?)&/', $url, $nonGreedy);
echo $nonGreedy[1]; // 输出: john
使用 U 修饰符(全局非贪婪)
可以使用 U 修饰符让整个模式变为非贪婪模式, 的作用相反(变成贪婪)。
$str = "<div>内容1</div><div>内容2</div>";
// 使用 U 修饰符,全局非贪婪
preg_match('/<div>(.*)<\/div>/U', $str, $matches);
print_r($matches[1]); // 输出: 内容1
// 在 U 模式下,加 ? 反而变成贪婪
preg_match('/<div>(.*?)<\/div>/U', $str, $matches);
print_r($matches[1]); // 输出: 内容1</div><div>内容2
实践建议
- 推荐使用 方式:在需要非贪婪的位置显式添加 ,代码更清晰
- 谨慎使用
U修饰符:它会反转整个模式的贪婪行为,可能导致混淆
// 推荐写法 - 只在需要的地方使用非贪婪 $pattern = '/<a href="(.*?)".*?>(.*?)<\/a>/'; // 不推荐使用 U 修饰符(可能造成混淆) $pattern = '/<a href="(.*)".*>(.*)<\/a>/U';
| 方法 | 语法 | 说明 |
|---|---|---|
| 单个量词非贪婪 | {n,m}? |
最常用,局部控制 |
| 全局非贪婪 | 模式加 U 修饰符 |
全局控制,慎用 |
最佳实践:在需要非贪婪匹配的位置使用 后缀,而不是使用 U 修饰符,这样代码更易读和可维护。