PHP项目正则分组如何提取内容

wen PHP项目 24

本文目录导读:

PHP项目正则分组如何提取内容

  1. 基本分组提取
  2. 命名分组(推荐)
  3. 实用示例
  4. 高级技巧
  5. 常见错误处理
  6. 总结建议

在PHP中,正则分组提取内容主要使用 preg_match()preg_match_all() 函数,以下是详细的使用方法:

基本分组提取

使用 preg_match() 提取单个匹配

$text = "我的手机号是:138-1234-5678";
$pattern = "/(\d{3})-(\d{4})-(\d{4})/";
if (preg_match($pattern, $text, $matches)) {
    print_r($matches);
    // 输出:
    // Array (
    //     [0] => 138-1234-5678  // 完整匹配
    //     [1] => 138            // 第1个分组
    //     [2] => 1234           // 第2个分组
    //     [3] => 5678           // 第3个分组
    // )
    echo "区号:".$matches[1];     // 138
    echo "中间:".$matches[2];     // 1234
    echo "尾号:".$matches[3];     // 5678
}

使用 preg_match_all() 提取所有匹配

$text = "姓名:张三,年龄:25,城市:北京";
$pattern = "/([^:]+):([^,]+)/";
if (preg_match_all($pattern, $text, $matches)) {
    print_r($matches);
    // 输出:
    // Array (
    //     [0] => Array ( [0] => 姓名:张三 [1] => 年龄:25 [2] => 城市:北京 )
    //     [1] => Array ( [0] => 姓名 [1] => 年龄 [2] => 城市 )
    //     [2] => Array ( [0] => 张三 [1] => 25 [2] => 北京 )
    // )
    // 提取所有姓名、年龄、城市
    foreach ($matches[1] as $key => $label) {
        echo "$label: " . $matches[2][$key] . "\n";
    }
}

命名分组(推荐)

PHP 5.5.0+ 支持命名分组,使代码更易读:

$text = "2024-01-15";
$pattern = "/(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})/";
if (preg_match($pattern, $text, $matches)) {
    // 通过名称访问
    echo "年份:".$matches['year'];   // 2024
    echo "月份:".$matches['month'];  // 01
    echo "日期:".$matches['day'];    // 15
    // 也可以通过索引访问
    echo $matches[0];  // 2024-01-15
    echo $matches[1];  // 2024
    echo $matches[2];  // 01
    echo $matches[3];  // 15
}

实用示例

提取URL参数

$url = "http://example.com?id=123&name=test&page=1";
$pattern = "/(?:[?&])(?P<key>[^=]+)=(?P<value>[^&]+)/";
preg_match_all($pattern, $url, $matches, PREG_SET_ORDER);
$params = [];
foreach ($matches as $match) {
    $params[$match['key']] = $match['value'];
}
print_r($params);
// Array ( [id] => 123 [name] => test [page] => 1 )

提取电子邮件信息

$email = "user@example.com";
$pattern = "/(?P<username>[^@]+)@(?P<domain>[^.]+)\.(?P<tld>\w+)/";
if (preg_match($pattern, $email, $matches)) {
    echo "用户名:".$matches['username'];  // user
    echo "域名:".$matches['domain'];      // example
    echo "顶级域:".$matches['tld'];       // com
}

替换中使用分组引用

$text = "2024-01-15";
// 将日期格式从 YYYY-MM-DD 改为 DD/MM/YYYY
$result = preg_replace(
    "/(\d{4})-(\d{2})-(\d{2})/",
    "$3/$2/$1",  // 引用分组
    $text
);
echo $result;  // 15/01/2024

使用命名分组的替换

$text = "2024-01-15";
$result = preg_replace_callback(
    "/(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})/",
    function($matches) {
        return "{$matches['day']}-{$matches['month']}-{$matches['year']}";
    },
    $text
);
echo $result;  // 15-01-2024

高级技巧

非捕获分组 (?:...)

$text = "The quick brown fox";
$pattern = "/(?:The|A) (\w+) (\w+) fox/";
if (preg_match($pattern, $text, $matches)) {
    print_r($matches);
    // 注意:分组[1]仍然是第一个捕获组(quick),因为(?:)不捕获
    // Array ( [0] => The quick brown fox [1] => quick [2] => brown )
}

贪婪与懒惰匹配

$text = "<div>内容1</div><div>内容2</div>";
// 贪婪匹配(会匹配尽可能多的内容)
$pattern1 = "/<div>(.*)<\/div>/";
preg_match($pattern1, $text, $matches1);
echo $matches1[1];  // 内容1</div><div>内容2
// 懒惰匹配(会匹配尽可能少的内容)
$pattern2 = "/<div>(.*?)<\/div>/";
preg_match($pattern2, $text, $matches2);
echo $matches2[1];  // 内容1

常见错误处理

// 错误:忘记转义特殊字符
$text = "价格是$99.99";
$pattern = "/价格是$(\d+)/";  // $会被解释为行尾
// 正确写法
$pattern = "/价格是\$(\d+)/";
// 错误:未检查匹配结果
if (preg_match($pattern, $text, $matches)) {
    // 安全使用 $matches[1]
}
// 使用 PREG_OFFSET_CAPTURE 获取位置信息
preg_match("/(\w+)@(\w+)/", "user@example", $matches, PREG_OFFSET_CAPTURE);
print_r($matches);
// 每个匹配包含值和位置

总结建议

  1. 优先使用命名分组 (?P<name>...),使代码更易读
  2. 总是检查 preg_match() 返回值(是否成功匹配)
  3. 使用非捕获分组 当不需要捕获时
  4. 注意特殊字符转义,特别是 、、 等
  5. 对于大量文本,考虑使用 preg_match_all() 配合 PREG_SET_ORDER

抱歉,评论功能暂时关闭!