PHP字符串包含判断:从基础strpos到高效str_contains,再到强大的正则表达式29

```html

在PHP编程中,判断一个字符串是否包含某个特定的字符或子字符串,是一项极其常见的操作。无论是数据验证、文本解析、搜索功能还是日志分析,这项能力都显得至关重要。PHP提供了多种内置函数来完成这一任务,它们各有特点,适用于不同的场景。作为一名专业的PHP开发者,理解这些函数的原理、用法、性能差异以及适用范围,是写出高效、健壮代码的基础。本文将深入探讨PHP中判断字符串是否存在字符的各种方法,并提供详细的代码示例和最佳实践。

一、最基础的判断:strpos() 与 stripos()

strpos() 函数是PHP中最常用且性能最优的字符串查找函数之一,用于查找一个字符串在另一个字符串中首次出现的位置。如果找到,它会返回子字符串在主字符串中的起始位置(从0开始计数);如果没有找到,则返回 false。

1. strpos() - 区分大小写


语法: strpos(string $haystack, string $needle, int $offset = 0): int|false
$haystack:要搜索的主字符串。
$needle:要查找的子字符串。
$offset (可选):从主字符串的哪个位置开始搜索,默认为0。

重点注意: 由于子字符串可能出现在主字符串的开头(即索引为0),而0在PHP中是一个“弱等于”false 的值。因此,在使用 strpos() 的返回值进行判断时,务必使用严格比较运算符 === 或 !==,以避免逻辑错误。<?php
$mainString = "Hello, world! Welcome to PHP programming.";
$searchChar = "world";
$searchChar2 = "php"; // 小写
$searchChar3 = "PHP"; // 大写
// 示例 1: 找到子字符串
if (strpos($mainString, $searchChar) !== false) {
echo "<p>'$mainString' 包含 '$searchChar'.</p>"; // 输出:'Hello, world! Welcome to PHP programming.' 包含 'world'.
} else {
echo "<p>'$mainString' 不包含 '$searchChar'.</p>";
}
// 示例 2: 区分大小写,找不到
if (strpos($mainString, $searchChar2) !== false) {
echo "<p>'$mainString' 包含 '$searchChar2'.</p>";
} else {
echo "<p>'$mainString' 不包含 '$searchChar2'.</p>"; // 输出:'Hello, world! Welcome to PHP programming.' 不包含 'php'.
}
// 示例 3: 区分大小写,找到
if (strpos($mainString, $searchChar3) !== false) {
echo "<p>'$mainString' 包含 '$searchChar3'.</p>"; // 输出:'Hello, world! Welcome to PHP programming.' 包含 'PHP'.
} else {
echo "<p>'$mainString' 不包含 '$searchChar3'.</p>";
}
// 示例 4: 使用 offset
$startOffset = 10; // 从索引10开始搜索
if (strpos($mainString, $searchChar, $startOffset) !== false) {
echo "<p>从索引 $startOffset 开始,'$mainString' 包含 '$searchChar'.</p>";
} else {
echo "<p>从索引 $startOffset 开始,'$mainString' 不包含 '$searchChar'.</p>"; // 输出:从索引 10 开始,'Hello, world! Welcome to PHP programming.' 不包含 'world'.
}
?>

2. stripos() - 不区分大小写


stripos() 函数与 strpos() 功能类似,唯一的区别是它在查找时不区分大小写

语法: stripos(string $haystack, string $needle, int $offset = 0): int|false<?php
$mainString = "Hello, world! Welcome to PHP programming.";
$searchChar = "php"; // 小写
if (stripos($mainString, $searchChar) !== false) {
echo "<p>'$mainString' (不区分大小写) 包含 '$searchChar'.</p>"; // 输出:'Hello, world! Welcome to PHP programming.' (不区分大小写) 包含 'php'.
} else {
echo "<p>'$mainString' (不区分大小写) 不包含 '$searchChar'.</p>";
}
?>

总结: strpos() 和 stripos() 是进行简单字符串包含判断的首选,它们的性能非常高。但请牢记使用 !== false 或 === false 进行严格比较。

二、PHP 8+ 的现代解决方案:str_contains()

PHP 8.0 引入了一个全新的函数 str_contains(),专门用于检查字符串是否包含另一个字符串。它的设计目标是提供一个更直观、更简洁的API,避免了 strpos() 返回0可能与 false 混淆的问题。

str_contains() - 区分大小写


语法: str_contains(string $haystack, string $needle): bool
$haystack:要搜索的主字符串。
$needle:要查找的子字符串。

返回类型: 直接返回 true 或 false。无需进行严格比较。<?php
$mainString = "Hello, world! Welcome to PHP programming.";
$searchChar = "world";
$searchChar2 = "PHP";
$searchChar3 = "python";
// 示例 1: 找到子字符串
if (str_contains($mainString, $searchChar)) {
echo "<p>'$mainString' 包含 '$searchChar'.</p>"; // 输出:'Hello, world! Welcome to PHP programming.' 包含 'world'.
} else {
echo "<p>'$mainString' 不包含 '$searchChar'.</p>";
}
// 示例 2: 找到子字符串
if (str_contains($mainString, $searchChar2)) {
echo "<p>'$mainString' 包含 '$searchChar2'.</p>"; // 输出:'Hello, world! Welcome to PHP programming.' 包含 'PHP'.
} else {
echo "<p>'$mainString' 不包含 '$searchChar2'.</p>";
}
// 示例 3: 未找到子字符串
if (str_contains($mainString, $searchChar3)) {
echo "<p>'$mainString' 包含 '$searchChar3'.</p>";
} else {
echo "<p>'$mainString' 不包含 '$searchChar3'.</p>"; // 输出:'Hello, world! Welcome to PHP programming.' 不包含 'python'.
}
?>

总结: 如果你的项目运行在 PHP 8.0 或更高版本,str_contains() 是判断字符串是否包含子字符串的首选。它代码更简洁、意图更明确、更不易出错。

三、获取匹配部分的函数:strstr() 与 stristr()

strstr() 和 stristr() 函数不仅能判断子字符串是否存在,还能返回从匹配点开始到主字符串结尾的部分。这对于需要进一步处理匹配内容或其后续部分的情况非常有用。

1. strstr() - 区分大小写


语法: strstr(string $haystack, string $needle, bool $before_needle = false): string|false
$haystack:要搜索的主字符串。
$needle:要查找的子字符串。
$before_needle (可选):如果设置为 true,则返回 $needle 之前的字符串部分;默认为 false,返回从 $needle 开始到结尾的部分。

<?php
$mainString = "example@";
$searchChar = "@";
$result = strstr($mainString, $searchChar);
if ($result !== false) {
echo "<p>从 '@' 开始的部分: " . $result . "</p>"; // 输出:从 '@' 开始的部分: @
} else {
echo "<p>未找到 '@'。</p>";
}
$resultBefore = strstr($mainString, $searchChar, true);
if ($resultBefore !== false) {
echo "<p>'@' 之前的部分: " . $resultBefore . "</p>"; // 输出:'@' 之前的部分: example
} else {
echo "<p>未找到 '@'。</p>";
}
?>

2. stristr() - 不区分大小写


与 strstr() 相同,但不区分大小写

语法: stristr(string $haystack, string $needle, bool $before_needle = false): string|false<?php
$mainString = "";
$searchChar = ".docx"; // 小写
$result = stristr($mainString, $searchChar);
if ($result !== false) {
echo "<p>从 '.docx' 开始的部分 (不区分大小写): " . $result . "</p>"; // 输出:从 '.docx' 开始的部分 (不区分大小写): .DOCX
} else {
echo "<p>未找到 '.docx'。</p>";
}
?>

总结: 如果你不仅需要判断存在性,还需要获取匹配或匹配之前/之后的部分,那么 strstr() 或 stristr() 是合适的选择。如果仅判断存在性,则 strpos() 或 str_contains() 更优。

四、强大的模式匹配:preg_match() (正则表达式)

当简单的子字符串查找无法满足需求时(例如,需要查找特定模式、匹配多个可能子字符串、或者根据字符类型进行匹配),正则表达式就派上用场了。PHP的 preg_match() 函数提供了强大的正则表达式匹配能力。

preg_match()


语法: preg_match(string $pattern, string $subject, array &$matches = null, int $flags = 0, int $offset = 0): int|false
$pattern:要搜索的正则表达式模式,通常以斜杠 / 包裹。
$subject:要搜索的主字符串。
$matches (可选):一个数组,用于存储所有匹配到的结果。
$flags (可选):匹配模式的附加标志。
$offset (可选):从主字符串的哪个位置开始搜索。

返回类型: 如果找到匹配项,返回 1;如果没有找到,返回 0;如果发生错误,返回 false。<?php
$mainString = "Contact us at info@ or support@.";
// 示例 1: 查找是否包含 "example" (简单模式)
if (preg_match("/example/", $mainString)) {
echo "<p>'$mainString' 包含 'example'.</p>"; // 输出:'Contact us at info@ or support@.' 包含 'example'.
}
// 示例 2: 查找是否包含 "contact" (不区分大小写)
if (preg_match("/contact/i", $mainString)) { // 'i' 修饰符表示不区分大小写
echo "<p>'$mainString' (不区分大小写) 包含 'contact'.</p>"; // 输出:'Contact us at info@ or support@.' (不区分大小写) 包含 'contact'.
}
// 示例 3: 查找是否包含一个邮箱地址模式
if (preg_match("/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/", $mainString)) {
echo "<p>'$mainString' 包含一个邮箱地址.</p>"; // 输出:'Contact us at info@ or support@.' 包含一个邮箱地址.
}
// 示例 4: 查找包含数字的子字符串
if (preg_match("/\d+/", $mainString)) { // \d 表示数字,+ 表示一个或多个
echo "<p>'$mainString' 包含数字.</p>";
} else {
echo "<p>'$mainString' 不包含数字.</p>";
}
?>

总结: preg_match() 是功能最强大的字符串查找方式,适用于复杂的模式匹配。然而,它的性能通常低于简单的字符串函数,且正则表达式的编写和理解门槛较高。对于简单的子字符串判断,不建议使用正则表达式。

五、统计子字符串出现次数:substr_count()

substr_count() 函数用于计算一个字符串中子字符串出现的次数。虽然它的主要目的是计数,但如果次数大于0,也意味着子字符串存在。

语法: substr_count(string $haystack, string $needle, int $offset = 0, ?int $length = null): int
$haystack:要搜索的主字符串。
$needle:要查找的子字符串。
$offset (可选):从主字符串的哪个位置开始搜索,默认为0。
$length (可选):在主字符串中搜索的长度。

返回类型: 子字符串出现的次数(整数)。<?php
$mainString = "apple, banana, apple, orange, apple";
$searchChar = "apple";
$searchChar2 = "grape";
$count1 = substr_count($mainString, $searchChar);
if ($count1 > 0) {
echo "<p>'$mainString' 包含 '$searchChar',共出现 $count1 次.</p>"; // 输出:'apple, banana, apple, orange, apple' 包含 'apple',共出现 3 次.
}
$count2 = substr_count($mainString, $searchChar2);
if ($count2 > 0) {
echo "<p>'$mainString' 包含 '$searchChar2',共出现 $count2 次.</p>";
} else {
echo "<p>'$mainString' 不包含 '$searchChar2'.</p>"; // 输出:'apple, banana, apple, orange, apple' 不包含 'grape'.
}
?>

总结: 如果你需要知道子字符串出现的具体次数,substr_count() 是理想选择。如果仅仅是判断是否存在,它也可以通过 > 0 来实现,但通常不如 strpos() 或 str_contains() 直接高效。

六、多字节字符串(UTF-8)的注意事项

上述所有函数(strpos(), stripos(), str_contains(), strstr(), stristr(), substr_count())都是针对字节而不是字符进行操作的。这意味着它们在处理多字节字符集(如UTF-8)时可能会产生非预期的结果,尤其是在计算长度或偏移量时。

如果你的应用程序涉及到多字节字符集(例如中文、日文、韩文等),你应该使用PHP的 扩展中提供的相应函数:
mb_strpos() 代替 strpos()
mb_stripos() 代替 stripos()
mb_strstr() 代替 strstr()
mb_stristr() 代替 stristr()
mb_substr_count() 代替 substr_count()

mb_str_contains() 目前尚未存在,但其行为与内置 str_contains() 相同,因为它只检查存在性,不涉及位置或长度计算。对于PHP 8+且涉及多字节字符的包含判断,原生的 str_contains() 仍然是安全的。<?php
$multibyteString = "你好,世界!PHP编程。";
$searchChar = "世界"; // 中文字符
// 使用 mb_strpos 处理多字节字符串
if (mb_strpos($multibyteString, $searchChar, 0, 'UTF-8') !== false) {
echo "<p>'$multibyteString' 包含 '$searchChar'. (通过 mb_strpos)</p>"; // 输出:'你好,世界!PHP编程。' 包含 '世界'. (通过 mb_strpos)
} else {
echo "<p>'$multibyteString' 不包含 '$searchChar'. (通过 mb_strpos)</p>";
}
// PHP 8+ str_contains 对多字节字符的包含判断仍然有效
if (str_contains($multibyteString, $searchChar)) {
echo "<p>'$multibyteString' 包含 '$searchChar'. (通过 str_contains)</p>"; // 输出:'你好,世界!PHP编程。' 包含 '世界'. (通过 str_contains)
}
?>

注意:在使用 mb_* 函数时,通常需要指定字符编码(例如 'UTF-8')。

七、总结与最佳实践

选择正确的字符串判断函数对于PHP应用程序的性能和可维护性至关重要。以下是一些最佳实践建议:

PHP 8+ 环境: 对于简单的字符串包含判断(不区分大小写或需要获取匹配位置以外的情况),强烈推荐使用 str_contains()。它语义清晰、代码简洁、性能优越。


PHP 7 及以下环境: 使用 strpos() 或 stripos()。记住,务必使用 === false 或 !== false 进行严格比较,以避免0带来的潜在逻辑错误。


需要获取匹配内容或其前后部分: 使用 strstr() 或 stristr()。


需要复杂模式匹配: 当需要匹配非固定字符串、或者根据字符类别、数量等进行高级匹配时,使用 preg_match()。但要权衡其性能开销和学习成本。


需要统计出现次数: 使用 substr_count()。


处理多字节字符集: 如果你的字符串可能包含UTF-8等多字节字符(例如中文、日文),并且你的操作涉及到字符位置或长度,请优先使用 mb_strpos()、mb_stripos() 等 mbstring 扩展提供的函数。对于纯粹的包含判断,str_contains() 在PHP 8+ 中依然适用。


性能考虑: 一般来说,直接的字符串查找函数(str_contains, strpos, strstr)比正则表达式(preg_match)更快,因为它们做了更少的通用性工作。在性能敏感的场景,应优先选择专用函数。



掌握这些函数及其适用场景,将使你在PHP字符串处理方面游刃有余。选择最合适的方法,不仅能提高代码效率,也能让代码更易读、更易维护。```

2025-10-14


上一篇:PHP高效统计文件行数:多种方法与性能深度解析

下一篇:PHP 数据转换数组:字符串、对象及更多高效技巧