如何让PHP的str_word_count()支持UTF-8并识别特殊字符
解决PHP 7中str_word_count()无法识别UTF-8特殊字符的词频统计问题
你的问题核心确实出在str_word_count()函数上——它默认只识别ASCII范围内的字母、数字和下划线作为单词的一部分,对UTF-8编码的特殊字符(比如Başka里的ş、Café里的é、weiß里的ß)以及包含点、数字、特殊符号的单词(比如J.J.Johanson、mike18、2€uros)处理得非常糟糕,要么截断单词,要么直接忽略这些非ASCII的部分。
下面是可行的解决方案,我推荐用正则分割的方式替代str_word_count():
方法一:使用preg_split结合Unicode正则分割单词
这种方式能完美支持UTF-8字符,还可以自定义允许出现在单词中的符号(比如点、撇号、欧元符号等),灵活性很高。
修改后的完整代码如下:
$freqData = array(); $keywords = "Başka, Başka, küskün küskün otomobil kaçtı buraya küskün otomobil neden kaçtı kaçtı buraya, oraya KISMEN @here #there J.J.Johanson hep. Danny:Where is mom? I don't know! Café est weiß for 2 €uros. My 2nd nickname is mike18."; $letterCount = 5; // 分割规则:匹配非Unicode字母、数字、点、撇号、欧元符号的字符作为分隔符 // u修饰符启用UTF-8模式,PREG_SPLIT_NO_EMPTY过滤空字符串 $words = preg_split('/[^\p{L}\p{N}\.\'€]+/u', $keywords, -1, PREG_SPLIT_NO_EMPTY); foreach ($words as $word) { // 可选:统一转为小写,避免大小写导致的重复统计(比如KISMEN和kismen) $word = mb_strtolower($word, 'UTF-8'); if (mb_strlen($word, 'UTF-8') >= $letterCount) { // 统计词频,存在则+1,不存在则初始化为1 $freqData[$word] = isset($freqData[$word]) ? $freqData[$word] + 1 : 1; } } // 用print_r输出数组,替代原代码的echo $freqData(直接echo数组只会显示Array) print_r($freqData);
代码说明:
- 正则
[^\p{L}\p{N}\.\'€]+:^表示取反,\p{L}匹配所有Unicode字母,\p{N}匹配所有Unicode数字,后面的\.\'€是允许出现在单词中的特殊符号,你可以根据需求添加或移除(比如不需要欧元符号就删掉€)。 mb_strtolower和mb_strlen确保对UTF-8字符串的处理正确,避免乱码或长度计算错误。- 原代码中
echo $freqData的错误:直接输出数组会显示Array,改用print_r或var_dump才能看到实际的词频数据。
方法二:自定义字符集调用str_word_count()(局限性较大)
str_word_count()其实支持第三个参数指定额外的单词字符,但对于UTF-8的多字节字符来说,这个参数只能传入单字节字符,无法处理像ş、é这类多字节的特殊字符,所以只能解决部分简单场景(比如允许@、#这类符号),无法解决带重音的UTF-8单词问题,因此不推荐。
示例(仅作参考):
// 仅能添加单字节符号,无法处理多字节UTF-8字符 $words = str_word_count($keywords, 1, '@#€');
这样修改后,你的词频统计就能正确识别所有UTF-8特殊字符和包含特定符号的单词了。
内容的提问来源于stack exchange,提问作者Meek
相关产品推荐
相关产品推荐

