strlen()按字节计数,制表符\t在UTF-8中占1字节,故长度为1;视觉宽度需按tabstop模拟列偏移计算,如tabstop=4时,“a\t”视觉长度为4。

strlen() 会把制表符 \t 当作 1 个字节算
PHP 的 strlen() 是按字节计数的,\t 在 UTF-8 编码下就是单字节(ASCII 值为 9),所以它和普通英文字符一样,长度为 1。这和你“肉眼看到的缩进宽度”无关——制表符本身不等于 4 个空格,只是终端/编辑器渲染时可能显示为 4 列宽。
如果你用 strlen("a\tb"),结果是 3,不是 5(哪怕它在 IDE 里看起来像 “a b”)。
想按“显示宽度”算长度?得自己处理制表符展开
所谓“含制表符的视觉长度”,本质是把每个 \t 替换成若干空格,再算总字符数。但空格数取决于当前列位置,不是固定值。比如:
-
"\t"在开头 → 从第 0 列开始,通常补到第 4 列 → 算 4 个空格 -
"a\t":'a' 占第 0 列,\t从第 1 列起,补到下一个 4 的倍数(即第 4 列)→ 补 3 个空格 -
"ab\t":'a','b' 占 0、1 列,\t从第 2 列起 → 补 2 个空格
标准做法是模拟制表位(如每 4 列一个),逐字符遍历并维护当前列偏移:
立即学习“PHP免费学习笔记(深入)”;
// 示例:按 tabstop=4 计算显示宽度
function visual_strlen($str, $tabstop = 4) {
$len = 0;
for ($i = 0; $i < strlen($str); $i++) {
$c = $str[$i];
if ($c === "\t") {
$len += $tabstop - ($len % $tabstop);
} else {
$len++;
}
}
return $len;
}mb_strlen() 对 \t 没影响,别指望它“修正”制表符
mb_strlen() 是为多字节字符(如中文、emoji)设计的,它依然把 \t 当作 1 个“字符”(code unit),不会改变其计数逻辑。无论你传 'UTF-8' 还是 '8bit',mb_strlen("a\tb") 还是 3。
它解决的是 "我" 这种在 UTF-8 下占 3 字节但应算作 1 个字符的问题,不是制表符渲染宽度问题。
实际项目中要注意:输入来源决定是否需要预处理
用户粘贴进来的文本、读取的配置文件、HTTP 请求体,都可能含真实 \t。如果你的业务逻辑依赖“显示宽度”(比如限制输入框可见长度、对齐日志输出、生成等宽表格),就不能只靠 strlen()。
-
前端已用
white-space: pre渲染?后端校验就得用visual_strlen()对齐 - 纯 API 接口、只做存储或简单校验?保持用
strlen()更轻量,也更符合 HTTP 协议层的字节语义 - 注意:Windows 行尾
\r\n中的\r和\n各算 1 字节,同样不参与“视觉宽度”计算,但会影响列偏移逻辑
制表符的“长度歧义”不在 PHP 函数缺陷,而在你没明确区分「存储长度」「编码字符数」「终端显示宽度」这三个概念。选哪个,取决于你的上下文到底要约束什么。











