PHP字符串包含判断:从`strpos`到`str_contains`,掌握多种高效方法85
在PHP编程中,判断一个字符串是否包含另一个子字符串是一个非常常见且基础的操作。无论是进行用户输入验证、路由匹配、内容过滤还是文本搜索,这项技能都至关重要。PHP提供了多种内置函数来完成这项任务,每种方法都有其特定的使用场景、性能特点以及版本兼容性。作为一名专业的程序员,理解这些方法的异同并根据具体需求选择最合适的一个,是提升代码质量和效率的关键。本文将深入探讨PHP中判断字符串包含关系的所有主流方法,从基础函数到现代新特性,助您全面掌握。
一、`strpos()`:最常用且经典的查找位置函数
`strpos()` 函数可能是PHP中判断字符串是否包含子字符串最常用的方法。它的作用是查找字符串在另一个字符串中首次出现的位置。如果找到了,它会返回子字符串开始位置的数字索引(从0开始);如果没有找到,则返回布尔值 `false`。
工作原理与注意事项
strpos(string $haystack, string $needle, int $offset = 0): int|false
`$haystack`:要搜索的字符串。
`$needle`:要查找的子字符串。
`$offset`:可选参数,指定从 `$haystack` 的哪个位置开始搜索。默认是0。
关键点:严格比较 `!== false`。由于 `strpos()` 返回的子字符串位置可能是 `0`(意味着子字符串在主字符串的开头),而 `0` 在非严格比较 (`!= false`) 中会被认为是 `false`,这会导致逻辑错误。因此,务必使用严格比较运算符 `!== false` 来判断是否找到子字符串。
示例代码
<?php
$mainString = "Hello, world! Welcome to PHP.";
$searchString1 = "world";
$searchString2 = "PHP";
$searchString3 = "hello"; // 注意大小写
$searchString4 = "start"; // 在开头
$searchString5 = "notfound";
// 示例1: 找到子字符串
if (strpos($mainString, $searchString1) !== false) {
echo "'{$mainString}' 包含 '{$searchString1}'"; // 输出: 'Hello, world! Welcome to PHP.' 包含 'world'
}
// 示例2: 找到子字符串
if (strpos($mainString, $searchString2) !== false) {
echo "'{$mainString}' 包含 '{$searchString2}'"; // 输出: 'Hello, world! Welcome to PHP.' 包含 'PHP'
}
// 示例3: 未找到 (区分大小写)
if (strpos($mainString, $searchString3) === false) {
echo "'{$mainString}' 不包含 '{$searchString3}' (区分大小写)"; // 输出: 'Hello, world! Welcome to PHP.' 不包含 'hello' (区分大小写)
}
// 示例4: 子字符串在开头 (位置为0)
$anotherString = "PHP is fun!";
if (strpos($anotherString, $searchString2) !== false) {
echo "'{$anotherString}' 包含 '{$searchString2}' (在开头)"; // 输出: 'PHP is fun!' 包含 'PHP' (在开头)
}
// 示例5: 未找到子字符串
if (strpos($mainString, $searchString5) === false) {
echo "'{$mainString}' 不包含 '{$searchString5}'"; // 输出: 'Hello, world! Welcome to PHP.' 不包含 'notfound'
}
// 示例6: 从指定偏移量开始搜索
$text = "apple, banana, apple pie";
if (strpos($text, "apple", 1) !== false) { // 从索引1开始搜索,会找到第二个'apple'
echo "从索引1开始,'{$text}' 包含 'apple'"; // 输出: 从索引1开始,'apple, banana, apple pie' 包含 'apple'
} else {
echo "从索引1开始,'{$text}' 不包含 'apple'";
}
?>
二、`stripos()`:大小写不敏感的查找
`stripos()` 函数与 `strpos()` 函数功能几乎相同,唯一的区别是 `stripos()` 在查找子字符串时会忽略大小写。这在需要进行不区分大小写的搜索时非常有用。
工作原理与示例
stripos(string $haystack, string $needle, int $offset = 0): int|false
参数与 `strpos()` 相同,返回值也是 `int|false`,因此同样需要使用严格比较 `!== false`。
示例代码
<?php
$mainString = "Hello, world! Welcome to PHP.";
$searchString1 = "world";
$searchString2 = "PHP";
$searchString3 = "hello"; // 小写
$searchString4 = "php"; // 小写
// 示例1: 找到子字符串 (大小写不敏感)
if (stripos($mainString, $searchString1) !== false) {
echo "'{$mainString}' 包含 '{$searchString1}' (大小写不敏感)"; // 输出: 'Hello, world! Welcome to PHP.' 包含 'world' (大小写不敏感)
}
// 示例2: 找到子字符串 (大小写不敏感)
if (stripos($mainString, $searchString3) !== false) {
echo "'{$mainString}' 包含 '{$searchString3}' (大小写不敏感)"; // 输出: 'Hello, world! Welcome to PHP.' 包含 'hello' (大小写不敏感)
}
// 示例3: 找到子字符串 (大小写不敏感)
if (stripos($mainString, $searchString4) !== false) {
echo "'{$mainString}' 包含 '{$searchString4}' (大小写不敏感)"; // 输出: 'Hello, world! Welcome to PHP.' 包含 'php' (大小写不敏感)
}
?>
三、`str_contains()`:PHP 8+ 的现代解决方案
从 PHP 8.0 版本开始,PHP 引入了一个全新的函数 `str_contains()`,旨在提供一个更简洁、更直观的方式来判断字符串是否包含子字符串。它直接返回一个布尔值,省去了对 `strpos()` 返回值进行严格比较的步骤,大大提高了代码的可读性。
工作原理与优势
str_contains(string $haystack, string $needle): bool
`$haystack`:要搜索的字符串。
`$needle`:要查找的子字符串。
优势:
简洁直观: 直接返回 `true` 或 `false`,无需进行额外判断。
代码可读性: 函数名清晰地表达了其意图。
性能优化: 通常比 `strpos() !== false` 更高效。
示例代码
<?php
$mainString = "The quick brown fox jumps over the lazy dog.";
$searchString1 = "fox";
$searchString2 = "dog";
$searchString3 = "cat"; // 不存在
$searchString4 = "quick"; // 在开头
$searchString5 = "FOX"; // 大小写不敏感,但 str_contains 区分
// 示例1: 找到子字符串
if (str_contains($mainString, $searchString1)) {
echo "'{$mainString}' 包含 '{$searchString1}'"; // 输出: 'The quick brown fox jumps over the lazy dog.' 包含 'fox'
}
// 示例2: 找到子字符串
if (str_contains($mainString, $searchString2)) {
echo "'{$mainString}' 包含 '{$searchString2}'"; // 输出: 'The quick brown fox jumps over the lazy dog.' 包含 'dog'
}
// 示例3: 未找到子字符串
if (!str_contains($mainString, $searchString3)) {
echo "'{$mainString}' 不包含 '{$searchString3}'"; // 输出: 'The quick brown fox jumps over the lazy dog.' 不包含 'cat'
}
// 示例4: 子字符串在开头
if (str_contains($mainString, $searchString4)) {
echo "'{$mainString}' 包含 '{$searchString4}' (在开头)"; // 输出: 'The quick brown fox jumps over the lazy dog.' 包含 'quick' (在开头)
}
// 示例5: str_contains 区分大小写
if (!str_contains($mainString, $searchString5)) {
echo "'{$mainString}' 不包含 '{$searchString5}' (区分大小写)"; // 输出: 'The quick brown fox jumps over the lazy dog.' 不包含 'FOX' (区分大小写)
}
?>
如果您需要大小写不敏感的 `str_contains()` 功能,并且运行在 PHP 8+ 环境,可以考虑结合 `strtolower()` 函数,或者继续使用 `stripos()`。<?php
$mainString = "Hello World";
$searchString = "world";
// 大小写不敏感的判断 (PHP 8+)
if (str_contains(strtolower($mainString), strtolower($searchString))) {
echo "'{$mainString}' 包含 '{$searchString}' (大小写不敏感)"; // 输出: 'Hello World' 包含 'world' (大小写不敏感)
}
?>
四、`strstr()` / `stristr()`:查找并返回子字符串
`strstr()` 函数用于查找子字符串的首次出现,并返回从该子字符串开始到主字符串结尾的部分。如果找不到子字符串,则返回 `false`。`stristr()` 是其大小写不敏感的版本。
工作原理与适用场景
strstr(string $haystack, string $needle, bool $before_needle = false): string|false
stristr(string $haystack, string $needle, bool $before_needle = false): string|false
`$haystack`:要搜索的字符串。
`$needle`:要查找的子字符串。
`$before_needle`:可选参数。如果设置为 `true`,`strstr()` 会返回 `$needle` 第一次出现之前的字符串部分。
虽然 `strstr()` 可以用来判断字符串包含关系(如果返回值不是 `false`,则说明包含),但它的主要目的是提取字符串,而不是简单地判断存在性。因此,如果仅仅需要判断包含,通常不建议使用 `strstr()`,因为它会创建并返回一个新的子字符串,可能造成不必要的内存开销。
示例代码
<?php
$email = "user@";
$domain = strstr($email, '@'); // 返回 "@"
$user = strstr($email, '@', true); // 返回 "user"
if ($domain !== false) { // 判断是否包含 '@' 符号
echo "邮件地址 '{$email}' 包含 '@' 符号。"; // 输出: 邮件地址 'user@' 包含 '@' 符号。
echo "域名部分: {$domain}"; // 输出: 域名部分: @
echo "用户名部分: {$user}"; // 输出: 用户名部分: user
}
$text = "PHP is a popular scripting language.";
if (stristr($text, "php") !== false) { // 大小写不敏感查找
echo "'{$text}' 包含 'php' (大小写不敏感)"; // 输出: 'PHP is a popular scripting language.' 包含 '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`:可选参数,如果提供了,匹配到的结果会存储到这个数组中。
`preg_match()` 返回 `1` 表示匹配成功,`0` 表示没有匹配到,`false` 表示发生错误。因此,判断是否包含字符串,只需要判断返回值是否为 `1`。
适用场景:
查找不固定的模式(例如手机号、邮箱、URL)。
模糊匹配(例如包含任意数字、字母或特定字符组合)。
需要提取匹配到的子模式。
不适用场景:
仅判断一个固定子字符串是否存在,此时 `strpos()` 或 `str_contains()` 更高效。
示例代码
<?php
$text = "The quick brown fox jumps over the lazy dog. My email is test@.";
// 示例1: 查找固定子字符串 (不建议用于此场景,效率不如strpos)
if (preg_match('/fox/', $text)) {
echo "'{$text}' 包含 'fox'"; // 输出: 'The quick brown fox jumps over the lazy dog. My email is test@.' 包含 'fox'
}
// 示例2: 大小写不敏感查找 (使用修饰符 i)
if (preg_match('/PHP/i', "php is great!")) {
echo "'php is great!' 包含 'PHP' (大小写不敏感)"; // 输出: 'php is great!' 包含 'PHP' (大小写不敏感)
}
// 示例3: 查找数字
if (preg_match('/\d+/', "There are 123 apples.")) {
echo "'There are 123 apples.' 包含数字"; // 输出: 'There are 123 apples.' 包含数字
}
// 示例4: 查找邮箱地址模式
if (preg_match('/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/', $text, $matches)) {
echo "'{$text}' 包含邮箱地址: {$matches[0]}"; // 输出: 'The quick brown fox jumps over the lazy dog. My email is test@.' 包含邮箱地址: test@
}
?>
六、`substr_count()`:计算子字符串出现次数
`substr_count()` 函数返回子字符串在主字符串中出现的次数。如果次数大于0,则说明主字符串包含该子字符串。
工作原理与示例
substr_count(string $haystack, string $needle, int $offset = 0, ?int $length = null): int
`$haystack`:要搜索的字符串。
`$needle`:要查找的子字符串。
`$offset`:可选参数,指定从 `$haystack` 的哪个位置开始搜索。
`$length`:可选参数,指定搜索的长度。
此函数返回一个整数。如果返回 `0`,表示没有找到;如果返回大于 `0` 的整数,表示找到了。
示例代码
<?php
$text = "apple, banana, apple pie, and another apple.";
$searchString = "apple";
$searchString2 = "orange";
$count1 = substr_count($text, $searchString);
$count2 = substr_count($text, $searchString2);
if ($count1 > 0) {
echo "'{$text}' 包含 '{$searchString}',共出现 {$count1} 次。"; // 输出: 'apple, banana, apple pie, and another apple.' 包含 'apple',共出现 3 次。
}
if ($count2 == 0) {
echo "'{$text}' 不包含 '{$searchString2}'。"; // 输出: 'apple, banana, apple pie, and another apple.' 不包含 'orange'。
}
?>
七、处理多字节(UTF-8)字符串:`mb_*` 系列函数
上述所有函数(`strpos()`, `stripos()`, `strstr()`, `stristr()`, `substr_count()`)都是针对单字节字符集(如ASCII)设计的。当处理包含中文、日文、韩文等非拉丁字符的多字节字符串(如UTF-8编码)时,这些函数可能会出现意外的结果,因为它们可能错误地将多字节字符的字节序列解释为多个单字节字符。
为了正确处理多字节字符串,PHP提供了 `mb_*` 系列函数(需要 `mbstring` 扩展开启),它们在操作前会考虑字符编码。
主要的 `mb_*` 函数
`mb_strpos()`:多字节版本 `strpos()`。
`mb_stripos()`:多字节版本 `stripos()`。
`mb_strstr()`:多字节版本 `strstr()`。
`mb_stristr()`:多字节版本 `stristr()`。
使用这些函数时,通常需要指定字符串的编码(如 'UTF-8')。
示例代码
<?php
$mbString = "你好世界,Welcome to PHP!";
$searchMbString = "世界";
$searchAsciiString = "Welcome";
$encoding = "UTF-8";
// 使用 strpos() 可能会有问题,但对于纯英文或在特定位置可能恰好返回正确
// if (strpos($mbString, $searchMbString) !== false) {
// echo "strpos 找到 '{$searchMbString}'"; // 可能输出错误或乱码,取决于字符集和PHP版本
// }
// 正确处理多字节字符串
if (mb_strpos($mbString, $searchMbString, 0, $encoding) !== false) {
echo "mb_strpos 找到 '{$searchMbString}'"; // 输出: mb_strpos 找到 '世界'
}
if (mb_strpos($mbString, $searchAsciiString, 0, $encoding) !== false) {
echo "mb_strpos 找到 '{$searchAsciiString}'"; // 输出: mb_strpos 找到 'Welcome'
}
$caseInsensitiveMbString = "你好编程世界";
if (mb_stripos($caseInsensitiveMbString, "世界", 0, $encoding) !== false) {
echo "mb_stripos 找到 '世界'"; // 输出: mb_stripos 找到 '世界'
}
?>
重要提示: 对于PHP 8+的 `str_contains()`,官方文档声明它会以字节形式检查,不处理多字节编码。这意味着如果您的子字符串跨越了多字节字符的边界,`str_contains()` 可能不会像您预期那样工作。但在绝大多数情况下,如果子字符串本身是多字节字符的完整序列,`str_contains()` 依然可以正确工作。如果遇到复杂的多字节场景,`mb_strpos()` 仍然是更保险的选择。
八、性能考量与最佳实践
在选择字符串包含判断方法时,除了功能需求,性能也是一个重要的考量因素。以下是对各种方法的性能大致排序和最佳实践建议:
`str_contains()` (PHP 8+): 对于简单判断子字符串是否存在,这是最推荐的方法。它在设计时就考虑到了效率,并且语义清晰,是 PHP 8 及更高版本的首选。
`strpos() !== false` 或 `stripos() !== false`: 对于 PHP 7.x 及更早版本,这是最推荐且高效的方法。务必使用严格比较 `!== false`。
`substr_count() > 0`: 虽然也能判断包含,但它的主要目的是计数。如果只需要判断是否存在,`strpos()` 通常更高效,因为它在找到第一个匹配后就可以停止。
`strstr()` / `stristr() !== false`: 用于判断包含时,效率低于 `strpos()`,因为它需要创建并返回一个新的子字符串。仅在您还需要提取子字符串时才考虑使用。
`preg_match()`: 正则表达式匹配的开销是最大的。除非您需要复杂的模式匹配功能,否则应避免使用它来做简单的子字符串判断。
`mb_*` 系列函数: 如果处理的是多字节字符集(如 UTF-8),那么为了确保正确性,即使性能略有牺牲,也应该优先使用 `mb_strpos()` 等 `mb_*` 函数。正确性在这里比微小的性能差异更重要。
总结与建议
PHP 8.0 及更高版本: 优先使用 `str_contains()` 进行简单、区分大小写的包含判断。如果需要不区分大小写,可以使用 `stripos()` 或 `str_contains(strtolower($haystack), strtolower($needle))`。
PHP 7.x 及更早版本: 使用 `strpos($haystack, $needle) !== false` 进行区分大小写的判断,使用 `stripos($haystack, $needle) !== false` 进行不区分大小写的判断。
多字节字符(中文、日文等): 始终使用 `mb_strpos()`、`mb_stripos()` 等 `mb_*` 函数,并指定正确的编码(例如 'UTF-8'),以避免乱码或错误判断。
复杂模式匹配: 只有在需要利用正则表达式的强大功能时才使用 `preg_match()`。
避免不必要的内存开销: 如果仅仅是判断是否存在,不要使用会返回子字符串的函数(如 `strstr()`)来达到目的,除非您确实需要该子字符串。
掌握这些方法,您将能够根据不同的项目需求和PHP版本,灵活、高效、准确地判断字符串中是否含有特定子字符串,从而编写出更健壮、性能更优的PHP代码。```
2025-10-30
Java String `replaceAll`与特殊字符:深度解析、陷阱与高效解决方案
https://www.shuihudhg.cn/131480.html
Python数据集格式深度解析:从基础结构到高效存储与实战选择
https://www.shuihudhg.cn/131479.html
PHP大文件分片上传:高效、稳定与断点续传的实现策略
https://www.shuihudhg.cn/131478.html
Python类方法中的内部函数:深度解析与高效实践
https://www.shuihudhg.cn/131477.html
Python函数互相引用:深度解析调用机制与高级实践
https://www.shuihudhg.cn/131476.html
热门文章
在 PHP 中有效获取关键词
https://www.shuihudhg.cn/19217.html
PHP 对象转换成数组的全面指南
https://www.shuihudhg.cn/75.html
PHP如何获取图片后缀
https://www.shuihudhg.cn/3070.html
将 PHP 字符串转换为整数
https://www.shuihudhg.cn/2852.html
PHP 连接数据库字符串:轻松建立数据库连接
https://www.shuihudhg.cn/1267.html