PHP 正则表达式完全指南

PHP提供了两种风格的正则表达式支持:PCRE(Perl Compatible Regular Expressions)和POSIX。由于POSIX已经废弃,本指南将专注于PCRE风格的正则表达式使用。

1. 基础知识

1.1 正则表达式函数

PHP中最常用的正则表达式函数:

// 查找匹配
preg_match()        // 返回第一个匹配
preg_match_all()    // 返回所有匹配

// 替换
preg_replace()      // 替换匹配的内容
preg_replace_callback() // 使用回调函数替换

// 分割
preg_split()        // 使用正则表达式分割字符串

// 过滤
preg_grep()         // 返回匹配模式的数组元素

1.2 基本语法示例

<?php

// 1. 基本匹配
$text = "Hello, my phone is 123-456-7890";

// 查找第一个匹配
if (preg_match('/\d+/', $text, $matches)) {
    echo "Found: " . $matches[0]; // 输出: 123
}

// 查找所有匹配
if (preg_match_all('/\d+/', $text, $matches)) {
    print_r($matches[0]); // 输出: Array([0]=>123 [1]=>456 [2]=>7890)
}

// 2. 使用不同分隔符
// 使用 / 分隔符
$pattern1 = '/pattern/';
// 使用 # 分隔符
$pattern2 = '#pattern#';
// 使用 ~ 分隔符
$pattern3 = '~pattern~';

2. 模式修饰符

PHP支持多种模式修饰符,用于改变匹配行为:

<?php

$text = "Hello WORLD\nNew Line";

// i - 不区分大小写
preg_match('/hello/i', $text);     // 匹配成功

// m - 多行模式
preg_match('/^New/m', $text);      // 匹配成功

// s - 点号匹配所有字符(包括换行)
preg_match('/Hello.*Line/s', $text); // 匹配成功

// x - 忽略空白字符和注释
$pattern = '/
    \d+  # 匹配数字
    \s*  # 可选的空白字符
    \w+  # 匹配单词
/x';

// u - Unicode模式
preg_match('/\p{Han}/u', '你好');  // 匹配中文字符

3. 常用匹配模式

3.1 字符匹配

<?php

$text = "PHP 7.4 is awesome! Price: $99.99";

// 匹配数字
preg_match_all('/\d+/', $text, $matches);

// 匹配单词
preg_match_all('/\w+/', $text, $matches);

// 匹配空白字符
preg_match_all('/\s+/', $text, $matches);

// 自定义字符类
preg_match_all('/[aeiou]/', $text, $matches); // 匹配元音字母

3.2 数量词

<?php

$text = "PHP PHPPPProgramming";

// * - 零次或多次
preg_match('/P*/', $text);

// + - 一次或多次
preg_match('/P+/', $text);

// ? - 零次或一次
preg_match('/P?/', $text);

// {n} - 精确n次
preg_match('/P{2}/', $text);

// {n,m} - n到m次
preg_match('/P{2,4}/', $text);

4. 高级特性

4.1 分组和捕获

<?php

$text = "John Smith, Jane Doe, Bob Johnson";

// 基本分组
preg_match_all('/(\w+)\s(\w+)/', $text, $matches);
print_r($matches);  // 包含完整匹配和子组

// 命名分组
preg_match_all('/(?P<first>\w+)\s(?P<last>\w+)/', $text, $matches);
print_r($matches['first']); // 访问命名组

// 非捕获组
preg_match_all('/(?:\w+)\s(\w+)/', $text, $matches);

4.2 前向查找和后向查找

<?php

$text = "Price: $100, Cost: $50";

// 正向前向查找
preg_match_all('/\d+(?=\s*dollars)/', $text, $matches);

// 负向前向查找
preg_match_all('/\d+(?!\s*dollars)/', $text, $matches);

// 正向后向查找
preg_match_all('/(?<=\$)\d+/', $text, $matches);

// 负向后向查找
preg_match_all('/(?<!\$)\d+/', $text, $matches);

5. 实用示例

5.1 数据验证

<?php

class Validator {
    // 验证电子邮件
    public static function validateEmail($email) {
        return (bool) preg_match(
            '/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/',
            $email
        );
    }

    // 验证中国手机号
    public static function validatePhone($phone) {
        return (bool) preg_match(
            '/^1[3-9]\d{9}$/',
            $phone
        );
    }

    // 验证密码强度
    public static function validatePassword($password) {
        return (bool) preg_match(
            '/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]{8,}$/',
            $password
        );
    }

    // 验证URL
    public static function validateUrl($url) {
        return (bool) preg_match(
            '/^https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_\+.~#?&\/=]*)$/',
            $url
        );
    }
}

5.2 文本处理

<?php

class TextProcessor {
    // 提取URL
    public static function extractUrls($text) {
        preg_match_all(
            '/https?:\/\/(?:[-\w.]|(?:%[\da-fA-F]{2}))+/',
            $text,
            $matches
        );
        return $matches[0];
    }

    // 清理HTML标签
    public static function stripTags($text) {
        return preg_replace('/<[^>]*>/', '', $text);
    }

    // 清理多余空白
    public static function cleanWhitespace($text) {
        return preg_replace('/\s+/', ' ', trim($text));
    }

    // 提取图片标签
    public static function extractImages($html) {
        preg_match_all('/<img[^>]+src=([\'"])?([^"\'>]+)/', $html, $matches);
        return $matches[2];
    }
}

6. 性能优化

6.1 正则表达式缓存

<?php

// 使用静态变量缓存编译后的正则表达式
class RegexCache {
    private static $patterns = [];

    public static function match($pattern, $subject) {
        if (!isset(self::$patterns[$pattern])) {
            // 首次使用时编译
            self::$patterns[$pattern] = $pattern;
        }
        return preg_match(self::$patterns[$pattern], $subject);
    }
}

6.2 优化建议

<?php

// 1. 使用适当的锚点
// 不好的写法
$pattern = '/\d+/';

// 好的写法
$pattern = '/^\d+$/';

// 2. 避免过度使用通配符
// 不好的写法
$pattern = '/.*foo.*/';

// 好的写法
$pattern = '/[^\/]*foo[^\/]*/';

// 3. 使用非捕获组
// 不好的写法
$pattern = '/(\d+)([a-z]+)/';

// 好的写法(当不需要捕获时)
$pattern = '/(?:\d+)(?:[a-z]+)/';

7. 错误处理

<?php

function safeRegex($pattern, $subject) {
    $result = false;
    try {
        // 设置错误处理器
        set_error_handler(function($severity, $message, $file, $line) {
            throw new ErrorException($message, 0, $severity, $file, $line);
        });

        $result = preg_match($pattern, $subject);

        restore_error_handler();
    } catch (Exception $e) {
        // 处理正则表达式错误
        error_log("Regex error: " . $e->getMessage());
        return false;
    }
    return $result;
}

8. 测试正则表达式

<?php

class RegexTest extends PHPUnit\Framework\TestCase {
    public function testEmailValidation() {
        $validator = new Validator();
        
        $this->assertTrue($validator->validateEmail('test@example.com'));
        $this->assertFalse($validator->validateEmail('invalid.email'));
        $this->assertTrue($validator->validateEmail('user@domain.co.uk'));
    }

    public function testPhoneValidation() {
        $validator = new Validator();
        
        $this->assertTrue($validator->validatePhone('13812345678'));
        $this->assertFalse($validator->validatePhone('12345678'));
    }
}

总结

PHP的正则表达式实现具有以下特点:

  1. 完整支持PCRE语法
  2. 提供丰富的内置函数
  3. 支持Unicode
  4. 可以使用不同的分隔符

最佳实践:

  1. 选择合适的分隔符,避免过度转义
  2. 使用命名捕获组提高代码可读性
  3. 适当使用模式修饰符
  4. 注意性能优化
  5. 做好错误处理
  6. 编写单元测试

注意事项:

  1. 正则表达式可能影响性能,需要谨慎使用
  2. 复杂的正则表达式应该添加注释
  3. 考虑使用缓存机制
  4. 处理大文本时要注意内存使用

记住:在PHP中使用正则表达式时,应该平衡效率和可维护性。过于复杂的正则表达式往往会带来维护困难,适当拆分复杂的匹配逻辑可以提高代码的可维护性。

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐