php如何统计字符出现次数 php字符串计数方法【应用】

count_chars() 能直接用但仅适用于ascii字符频次统计,对中文、emoji等utf-8多字节字符会错误拆分为字节计数;安全做法是配合mbstring扩展,用mb_strlen()和mb_substr($str, $i, 1, ‘utf-8’)逐字符遍历统计。

php如何统计字符出现次数 php字符串计数方法【应用】

count_chars() 能不能直接用?

能,但只适合统计 ASCII 字符频次,且返回格式反直觉。它默认返回一个 256 元素的数组,索引是 ASCII 码(0–255),值是该字符出现次数。中文、emoji、UTF-8 多字节字符会直接被拆成多个字节计数,结果完全不可信。

  • "你好" 调用 count_chars($str),实际统计的是 UTF-8 编码的 6 个字节(每个汉字 3 字节),不是 2 个字符
  • 想查某个具体字符(比如 "a")出现几次?得写 $arr[ord('a')],绕且易错
  • 如果只需要一个字符的频次,用它反而比手动遍历还重

mb_substr() + 循环才是 UTF-8 安全的底线做法

PHP 原生没有「按字符而非字节」统计的单函数,必须依赖多字节扩展。核心逻辑:用 mb_strlen() 获取真实字符数,再用 mb_substr() 逐个切出字符比对。

  • 确保已启用 mbstring 扩展(php -m | grep mbstring 可确认)
  • 必须显式指定编码,如 mb_substr($str, $i, 1, 'UTF-8'),漏掉第三个参数会退化为 substr()
  • 别用 for ($i = 0; $i 然后 <code>mb_substr($str, $i, 1) —— 每次调用都重新算长度,性能差;先存 $len = mb_strlen($str, 'UTF-8')

示例(统计 "a" 在字符串中出现次数):

$str = "a你好a世界"; $count = 0; $len = mb_strlen($str, 'UTF-8'); for ($i = 0; $i < $len; $i++) {     if (mb_substr($str, $i, 1, 'UTF-8') === 'a') {         $count++;     } }

正则 preg_match_all() 适合模式化匹配场景

当你要统计的不是固定字符,而是符合某规则的片段(比如所有数字、所有中文、所有邮箱里的 @ 符号),preg_match_all() 更直接,且天然支持 UTF-8(加 u 修饰符)。

立即学习PHP免费学习笔记(深入)”;

  • 统计中文字符数:preg_match_all('/p{Han}/u', $str, $matches),结果是 count($matches[0])
  • 统计所有标点:preg_match_all('/p{P}/u', $str, $matches)
  • 注意:空字符串或无匹配时,$matches 是空数组,count($matches[0]) 不会报错但返回 0
  • 性能比循环略低,但代码更清晰,尤其规则复杂时

自定义函数封装要注意编码参数透传

很多人封装成 mb_str_count($str, $char) 后发现中文不生效,问题几乎都出在没把编码参数往下传。默认用 mb_internal_encoding() 不可靠,它可能被其他代码改过,或根本没设。

  • 必须让调用者能指定编码,且默认值设为 'UTF-8',而不是依赖全局设置
  • 对单字符统计,别忘了用 mb_strlen($char, $encoding) === 1 校验输入是否真为单个 Unicode 字符,避免传入多字节字符串导致逻辑错乱
  • 如果统计目标是子串(不止一个字符),要用 mb_strpos() 循环查找,不能用 strpos()

真正容易被忽略的点:PHP 的字符串函数对编码极其敏感,mb_* 系列函数不传编码参数 ≠ 默认 UTF-8,而是默认用 mb_internal_encoding() 当前值 —— 这个值在 CLI 和 Web SAPI 下可能不同,线上出问题往往就卡在这儿。