PHP用substr提取指定字符后内容需先用strpos找位置,因substr只认字节偏移;处理UTF-8中文须用mb_substr和mb_strpos并显式指定'UTF-8'编码。

PHP 用 substr 提取指定字符之后的内容,必须先找位置
直接用 substr 无法“按字符切”,它只认字节偏移。想提取 "user@example.com" 中 @ 后面的 "example.com",得先用 strpos 找到 @ 的位置,再算起始点。
常见错误是写成 substr($str, '@') —— 这会报 Warning:substr() expects parameter 2 to be int,因为第二个参数必须是整数。
-
strpos($str, '@')返回首次出现位置(从 0 开始),没找到返回false,记得判空 - 起始偏移 =
strpos($str, '@') + 1,加 1 是为了跳过@本身 - 如果只要后面部分,第三个参数(长度)可省略;若需限制长度,传入正整数即可
$str = 'name@domain.tld'; $pos = strpos($str, '@'); $result = ($pos !== false) ? substr($str, $pos + 1) : ''; // $result === 'domain.tld'
中文或 UTF-8 字符串别用 substr 直接切
PHP 默认的 substr 按字节操作,遇到中文、emoji 或带重音符号的字母(如 café)会截断乱码。比如 substr('你好世界', 2) 可能输出乱码而非 '好世界'。
解决办法是换用多字节安全函数:mb_substr,但注意它默认使用 mb_internal_encoding() 设定的编码,通常要显式指定 'UTF-8'。
立即学习“PHP免费学习笔记(深入)”;
- 找位置也得用
mb_strpos($str, '@', 0, 'UTF-8'),否则位置算错 -
mb_substr($str, $pos + 1, null, 'UTF-8')中null表示取到末尾 - 不设编码参数时,部分环境可能 fallback 到
ISO-8859-1,结果不可靠
更简洁的写法:用 explode 或 strrchr?
如果目标只是“第一次/最后一次出现某字符后的部分”,有更短的内置方案:
-
end(explode('@', $str))—— 简单但不推荐:explode会拆完整个字符串,浪费内存;且end()修改数组内部指针,可能影响后续逻辑 -
ltrim(strrchr($str, '@'), '@')——strrchr返回从*最后一次*@开始的子串(含@),所以要用ltrim去掉开头的@ -
strrchr对单字符有效,但不支持多字符分隔符(如"<!--");也不处理未找到的情况(返回false)
实际项目中,还是推荐 strpos + substr/mb_substr 组合:语义清晰、可控性强、性能稳定。
容易被忽略的边界情况
真实数据里常有空字符串、全角 @(如 @)、前后空格、多个 @。这些不会报错,但结果可能不是你想要的。
- 输入为空或
null时,strpos返回false,直接传给substr会变成substr($str, false)→ 等价于substr($str, 0),悄悄返回原串 - 全角符号需单独匹配:
mb_strpos($str, '@', 0, 'UTF-8'),和半角@不是同一个字符 - 邮箱类场景建议用
filter_var($str, FILTER_VALIDATE_EMAIL)预校验,而不是仅依赖切分
真正健壮的提取,永远始于对输入的假设检验,而不是对函数行为的乐观预期。



















