Menu

PHP strpos():查找子串出现的位置

strpos($haystack, $needle) 返回 $needle 第一次出现的位置,找不到时返回 false。学习 !== false 判断、不区分大小写的 stripos、用 strrpos 找最后一处匹配,以及查找所有出现位置。

本页包含可运行的编辑器。编辑、运行,立即查看输出。

strpos($haystack, $needle) 返回 $needle 在 $haystack 中第一次出现的位置(从 0 开始计算),如果不存在则返回 false。务必用 !== false 检查结果,因为匹配在开头时返回 0。

如果在 PHP 8 中只需要“是”或“否”的答案,str_contains() 更清楚。位置本身有用时再用 strpos()。

语法

strpos(string $haystack, string $needle, int $offset = 0): int|false

查找区分大小写。$offset 指定从哪里开始查找;负数偏移量从字符串末尾开始计算。

!== false 陷阱

在宽松比较(==)下,0 和 false 相等。所以只要判断不是严格比较,位置 0 的匹配就会被当成“没找到”。

同样的规则也适用于 stripos()、strrpos() 和 array_search(),它们在真正找到匹配时都可能返回 0。

用 stripos 不区分大小写地查找

stripos() 接收同样的参数,忽略 ASCII 字母的大小写。

用 strrpos 查找最后一处匹配

strrpos() 返回最后一处匹配的位置。获取文件扩展名或路径的最后一段时,通常就这么写。

如果处理的是文件名,pathinfo($file, PATHINFO_EXTENSION) 可以直接帮你完成。在某个位置截断字符串的方法见 substr() 页面。

从指定偏移量开始查找

第三个参数用来跳过字符串的开头部分。负数偏移量表示从末尾往前数那么多个字符开始。

查找所有出现位置

strpos() 只找一处匹配。要找出全部,就在循环里把偏移量移到每次匹配之后:

只需要次数?substr_count($text, 'the') 更简短。按模式查找时,preg_match_all() 配合 PREG_OFFSET_CAPTURE 会返回每一处匹配及其位置。

中文和日文文本:字节位置与字符位置

strpos() 能正确找到多字节文本,但它返回的数字以字节为单位。在 UTF-8 中,假名和常用汉字各占 3 个字节,所以在全是汉字或假名的文本里,字节位置是字符位置的三倍;在混合文本里,两者的差距就没那么好算了。mb_strpos() 返回字符位置,这正是 mb_substr() 需要的。

把两者混着用是一个经典 bug:把 strpos() 的结果传给 mb_substr(),起点会偏后太多。strpos 配 substr,mb_strpos 配 mb_substr。

常见问题

PHP 中 strpos() 返回什么?

返回第一处匹配的位置(整数,从 0 开始计算),找不到时返回 false。strpos('hello', 'l') 返回 2。

为什么 strpos() 要配合 !== false 使用?

因为匹配在最开头时返回 0,而 0 == false 为真。if (strpos($s, 'a')) 会把位置 0 的匹配当成“没找到”。始终写成 strpos($s, 'a') !== false。

strpos、stripos 和 strrpos 有什么区别?

strpos() 查找第一处匹配,区分大小写。stripos() 查找第一处匹配,忽略大小写。strrpos() 查找最后一处匹配。strripos() 查找最后一处匹配,忽略大小写。

判断字符串是否包含某段文本,用 strpos 还是 str_contains?

PHP 8 中用 str_contains($haystack, $needle),它直接返回 true 或 false,没有位置 0 的陷阱。需要知道具体位置时才用 strpos()。

strpos 怎么处理中文、日文文本?

strpos() 能正确找到中日文文本,但返回的是字节位置。如果要把这个位置传给 mb_substr() 或展示给用户,用 mb_strpos(),它返回按字符计算的位置。

Coddy 编程语言插图

和 Coddy 一起学编程

开始