preg_match返回false表示正则表达式存在语法错误或pcre内部错误,而非未找到匹配;1是找到第一个匹配,0是未找到;可通过preg_last_error()获取具体错误码以调试。

PHP中使用正则表达式进行模式匹配,主要是通过
preg_match
preg_match
int preg_match ( string $pattern , string $subject [, array &$matches [, int $flags = 0 [, int $offset = 0 ]]] )
$pattern
/
#
~
$subject
&$matches
$matches[0]
$flags
PREG_OFFSET_CAPTURE
$offset
$subject
一个简单的例子:
立即学习“PHP免费学习笔记(深入)”;
<?php
$text = "我的电话是:138-0000-1234,工作电话是:010-8888-9999。";
$pattern = '/(\d{3})-(\d{4})-(\d{4})/'; // 匹配手机号格式
if (preg_match($pattern, $text, $matches)) {
echo "找到一个手机号: " . $matches[0] . "\n";
echo "区号: " . $matches[1] . "\n";
echo "中间四位: " . $matches[2] . "\n";
echo "最后四位: " . $matches[3] . "\n";
} else {
echo "没有找到手机号。\n";
}
// 尝试匹配一个不存在的模式
$pattern2 = '/[a-z]+/';
if (preg_match($pattern2, $text, $matches2)) {
echo "找到字母串: " . $matches2[0] . "\n";
} else {
echo "没有找到字母串。\n";
}
?>这个例子展示了
preg_match
$matches
preg_match
false
这是个挺让人困惑的问题,因为大多数情况下我们期待它返回0(没找到)或1(找到了)。但如果
preg_match
false
我个人就遇到过好几次这种情况,尤其是在动态构建正则表达式时,不小心写错了模式,比如:
/
/
当
preg_match
false
preg_last_error()
<?php
// 一个错误的正则表达式:定界符不匹配
$brokenPattern = '/hello/'; // 假设我本意是 /hello/,但写成了这样
$subject = "hello world";
// 故意制造一个错误,例如模式中包含未转义的定界符
$faultyPattern = '/http://example.com/'; // 这里的第二个'/'没有转义
if (preg_match($faultyPattern, $subject, $matches)) {
echo "匹配成功: " . $matches[0] . "\n";
} else {
echo "匹配失败或错误发生。\n";
$errorCode = preg_last_error();
// 常见的错误码:
// PREG_NO_ERROR (0) - 没有错误
// PREG_INTERNAL_ERROR (1) - PCRE内部错误
// PREG_BACKTRACK_LIMIT_ERROR (2) - 回溯限制错误
// PREG_RECURSION_LIMIT_ERROR (3) - 递归限制错误
// PREG_BAD_UTF8_ERROR (5) - UTF-8数据错误
// PREG_BAD_UTF8_OFFSET_ERROR (6) - UTF-8偏移量错误
echo "错误代码: " . $errorCode . "\n";
// 根据错误代码,你可以判断具体是什么问题
if ($errorCode === PREG_DELIMITER_ERROR) {
echo "错误详情: 定界符错误。\n";
}
}
?>通过检查
preg_last_error()
preg_match
preg_match_all
这是两个非常常用但目的不同的函数。简单来说:
preg_match
preg_match
preg_match_all
preg_match_all
它们返回的
$matches
preg_match
$matches
preg_match_all
$matches
$flags
PREG_PATTERN_ORDER
PREG_SET_ORDER
让我们看个例子来直观感受一下:
<?php
$text = "邮箱1: test@example.com, 邮箱2: user@domain.org, 邮箱3: info@service.net";
$pattern = '/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/';
echo "--- 使用 preg_match ---\n";
if (preg_match($pattern, $text, $match)) {
echo "找到第一个邮箱: " . $match[0] . "\n";
print_r($match);
} else {
echo "没有找到邮箱。\n";
}
echo "\n--- 使用 preg_match_all ---\n";
if (preg_match_all($pattern, $text, $allMatches)) {
echo "找到所有邮箱:\n";
// 默认是 PREG_PATTERN_ORDER,即 $allMatches[0] 是所有完整的匹配,
// $allMatches[1] 是所有第一个捕获组的匹配,以此类推。
foreach ($allMatches[0] as $email) {
echo "- " . $email . "\n";
}
print_r($allMatches);
} else {
echo "没有找到邮箱。\n";
}
// 另一种 PREG_SET_ORDER 模式
echo "\n--- 使用 preg_match_all (PREG_SET_ORDER) ---\n";
if (preg_match_all($pattern, $text, $allMatchesSetOrder, PREG_SET_ORDER)) {
echo "找到所有邮箱 (PREG_SET_ORDER):\n";
// 这种模式下,每个匹配都是一个独立的子数组
foreach ($allMatchesSetOrder as $matchEntry) {
echo "- " . $matchEntry[0] . "\n";
}
print_r($allMatchesSetOrder);
}
?>可以看到,当我们需要提取所有符合条件的项时,
preg_match_all
preg_match
preg_match
处理中文字符或者一些多字节字符(如日文、韩文)时,最常见的问题就是匹配不准确或者出现乱码。这是因为PCRE库默认是按字节处理字符串的,而不是按字符。当遇到UTF-8编码的字符串时,一个中文字符可能由多个字节组成,如果正则引擎按字节匹配,就会出错。
解决方案很简单,但很重要:使用u
在正则表达式的定界符后面加上
u
<?php
$chineseText = "你好世界,这是一个中文文本。";
// 错误的匹配方式(不加 u 修饰符)
$patternNoU = '/[\u4e00-\u9fa5]+/'; // 匹配中文字符范围
echo "--- 不使用 'u' 修饰符 ---\n";
if (preg_match($patternNoU, $chineseText, $matchesNoU)) {
echo "匹配到 (可能不准确): " . $matchesNoU[0] . "\n";
} else {
echo "没有匹配到或匹配错误。\n";
// 在某些PHP版本或配置下,不加'u'可能会直接导致错误
echo "错误代码: " . preg_last_error() . "\n";
}
// 正确的匹配方式(加上 u 修饰符)
$patternWithU = '/[\x{4e00}-\x{9fa5}]+/u'; // 匹配中文字符范围,并使用u修饰符
// 注意:在模式中直接写Unicode字符范围时,需要使用 \x{} 语法,或者直接在字符串中包含中文字符。
// 比如 '/[你好]+/u' 也是可以的。
echo "\n--- 使用 'u' 修饰符 ---\n";
if (preg_match($patternWithU, $chineseText, $matchesWithU)) {
echo "正确匹配到: " . $matchesWithU[0] . "\n";
} else {
echo "没有匹配到。\n";
}
// 匹配特殊字符,比如点号 '.' 默认匹配任意字符(除了换行),如果要匹配字面意义上的点,需要转义
$specialCharText = "这是个文件.txt";
$patternDot = '/\.txt/u'; // 匹配 ".txt" 字符串,注意点号需要转义
echo "\n--- 匹配特殊字符 ---\n";
if (preg_match($patternDot, $specialCharText, $matchesDot)) {
echo "匹配到文件后缀: " . $matchesDot[0] . "\n";
} else {
echo "没有匹配到文件后缀。\n";
}
?>对于特殊字符,比如
.
*
+
?
[
]
(
)
{}
\
|
^
$
\
preg_match
虽然
preg_match
一个典型的陷阱是“灾难性回溯”(Catastrophic Backtracking)。这通常发生在模式中包含重复的、可以匹配空字符串或重叠的量词时,例如
^(a+)+$
(.+)*
避免这种问题的方法包括:
*
+
?
{n,m}?
*?
+?
??
{n,m}?(?:...)
(?>...)
*+
++
?+
{n,m}+^(a+)+$
^(?>a+)+$
\d+
.*
strpos
strstr
preg_match
preg_match
举个“灾难性回溯”的例子:
<?php
// 这个模式在匹配长字符串时,如果字符串不符合模式,会导致严重的性能问题
$badPattern = '/(a+)+b/';
$longString = str_repeat('a', 30) . 'c'; // 'c'使得匹配失败
$startTime = microtime(true);
if (preg_match($badPattern, $longString)) {
echo "匹配成功。\n";
} else {
echo "匹配失败。\n";
}
$endTime = microtime(true);
echo "耗时 (糟糕模式): " . ($endTime - $startTime) . " 秒\n";
// 使用原子组避免回溯
$goodPattern = '/(?>a+)b/'; // 或者 /(a++)b/
$startTime = microtime(true);
if (preg_match($goodPattern, $longString)) {
echo "匹配成功。\n";
} else {
echo "匹配失败。\n";
}
$endTime = microtime(true);
echo "耗时 (优化模式): " . ($endTime - $startTime) . " 秒\n";
?>你会发现,在长字符串且匹配失败的情况下,优化后的模式几乎是瞬间完成,而未优化的模式可能会卡住很久。在实际开发中,尤其是在处理用户输入或大量文本时,对正则表达式的性能考量是不可忽视的。
以上就是PHP怎样使用正则表达式?preg_match模式匹配的详细内容,更多请关注php中文网其它相关文章!
PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号