strlen($string) 返回字符串的字节长度。要得到字符数(处理中文、日文、带重音的字母和 emoji 时你需要的正是它),用 mb_strlen($string)。对于纯英文文本,两者的结果相同。
空格、标点和换行都算在内。strlen("a b\n") 是 4。
UTF-8 中的字节和字符
PHP 字符串是字节序列,而 UTF-8 中每个字符占用的字节数不同:ASCII 字母和数字占 1 个,é 或 ж 这样的字母占 2 个,假名、常用汉字和 € 这样的符号占 3 个,大多数 emoji 和 𠮷 这样的生僻字占 4 个。strlen() 把字节加起来,mb_strlen() 数的是字符。用文本转二进制工具可以看到任意字符串背后的字节。
字节数重要时用 strlen():按字节限制长度的数据库列、文件大小、二进制协议。凡是给人看的内容都用 mb_strlen():字数统计、“最多 20 个字”的规则、用 mb_substr() 截取文本。
emoji 和由多个码位组成的字符
mb_strlen() 统计的是 Unicode 码位。有些在读者看来是一个字符的东西,其实是几个码位连在一起:家庭 emoji、旗帜、肤色,或者一个字母加一个组合重音符。
要统计读者眼中的单个字符(字素簇),需要 intl 扩展中的 grapheme_strlen():
echo grapheme_strlen('👨👩👧'); // 1
echo grapheme_strlen('🇯🇵'); // 1
对于中文或日文表单上的字数统计,mb_strlen() 通常就够了:每个汉字和假名都是一个码位。
用 mb_strwidth 计算显示宽度
在终端或等宽排版中,一个全角的中文或日文字符占两列,而半角片假名或拉丁字母占一列。mb_strwidth() 返回的就是这个宽度,“全角字符算 2 个字”这类规则通常指的正是它。
判断字符串是否为空
最清楚的写法是和 '' 严格比较。strlen($s) === 0 的结果相同。empty($s) 则不一样:它对字符串 "0" 也返回 true,而在很多表单里 "0" 是一个有效的答案。
只有空格的字符串不是空的。如果只有空格也应该算作没有内容,先用 trim() 处理一下。
strlen(null) 和非字符串
strlen() 需要一个字符串。传入 null 仍然返回 0,但从 PHP 8.1 开始会打印一条弃用提示:
Deprecated: strlen(): Passing null to parameter #1 ($string) of type string is deprecated in /home/index.php on line 2
传入数组会抛出 TypeError: strlen(): Argument #1 ($string) must be of type string, array given。
先转换类型或给一个默认值,比如 strlen($value ?? '')。整数会被转换成字符串,所以 strlen(12345) 是 5。要统计数组元素,用 count()。
校验用户输入的长度
一个典型的规则:去掉首尾空格后,用户名长度为 3 到 16 个字符。用 mb_strlen(),这样日文或中文名字按字符而不是按字节计算。
如果把 mb_strlen() 换成 strlen(),やまだたろう 会被算成 18,并因为太长而被拒绝,尽管它只有六个字符。
常见问题
PHP 中怎么获取字符串的长度?
strlen($s) 返回字节数,mb_strlen($s) 返回字符数。对于纯英文文本两者相同;对于中文、日文、带重音的字母或 emoji,用 mb_strlen()。
为什么 strlen() 对中文、日文文本返回的长度不对?
它没有错,它数的是字节。UTF-8 中假名、常用汉字各占 3 个字节,所以 strlen('日本語') 是 9,而 mb_strlen('日本語') 是 3。
怎么统计包含 emoji 的字符串的字符数?
mb_strlen() 统计的是 Unicode 码位,所以简单的 emoji 算 1 个,但由多个码位组成的 emoji(家庭、旗帜、肤色)会算成多个。intl 扩展中的 grapheme_strlen() 统计的是读者眼中的一个字符。
PHP 中 strlen 和 count 有什么区别?
strlen() 测量字符串,count() 统计数组的元素个数。在 PHP 8 中把数组传给 strlen() 会抛出 TypeError。
PHP 中怎么判断字符串是否为空?
和空字符串比较:$s === '',或者 strlen($s) === 0。不要用 empty($s) 做这件事,因为它把字符串 "0" 也当作空。