wordpress UTF8 中文字数统计插件
最近想在博客中实现这样的功能:“本文字数XXX,继续阅读…”。在网上找了一款Word Count Plugin for WordPress,作者是 Murray Williams,可惜它只能统计英文单词数,却不能统计中文字数。我下载了源码,自己动手修改,实现了想要的功能。修改过程中涉及了PHP语言中如何使用正则表达式来匹配中文,于是我把过程写这在里。
该插件的核心部分是这样的:
1 2 3 4 5 6 7 8 | function mtw_wordcount() { global $page, $pages; if ( !function_exists('str_word_count') ) { return str_word_count(strip_tags($pages[$page-1])); } else { return count(explode(" ",strip_tags($pages[$page-1]))); } } |
看来,它并没有自己来数字数,还是调用PHP函数str_word_count实现的。查文档,找到它的官方文档,http://us2.php.net/str_word_count。它能统计字串中的英文单词数,按要求返回单词数目或单方数组。其原理是以默认或指定的分隔符来将字串分隔,再逐个统计。由于该函数对utf8无效,应该使用utf8版:str_word_count_utf8。
英文的单词之间有空格等分隔符,中文的应该怎样统计呢?由于Wordpress的中文字符编码为utf8,我们就从utf8入手。根据以前我写过一篇文章《匹配中文的正则表达式》可知,在utf8中,匹配单个汉字的正则式是[\x80-\xff]{3}。这样一来,只要将中文的每一个单字视为一个英语单词来处理,那么统计出来的单词数量就应该是正确的。例如,
你好,世界。Hello world.
我的处理方法是,将所有的中文单字替换成两边带空格的英文字母a,即使用正则表达式:
1 | $string = preg_replace('/[\x80-\xff]{3}/', ' a ', $string); |
考虑到中文标点不计入总数,前边还应该有一条:
1 2 | $string = $string = preg_replace("/~|!|`|·|#|¥|%|…|—| (|)|+|-|=|{|}|[|]|\\|||“|”|’|‘|;|:|《|》|〈|〉|、|?|。|,/",' ',$string); |
此时运行程序,得到正确的结果:6。
wordpress UTF8 中文字数统计插件完整的PHP程序是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | <?php load_plugin_textdomain('mtw-wordcount','wp-content/plugins/mtw-wordcount'); /* Call this from inside "The Loop" (see WordPress documentation) to get a WordCount of the current posting. Function RETURNS the Word Count as a value, it does not automatically display (ie. 'echo') the value. */ define("WORD_COUNT_MASK", "/\p{L}[\p{L}\p{Mn}\p{Pd}'\x{2019}]*/u"); function str_word_count_utf8($string, $format = 0) { $string = $string = preg_replace("/~|!|`|·|#|¥|%|…|—|(|)|+|-|=|{|}|[|]|\\|||“|”|’|‘|;|:|《|》|〈|〉|、|?|。|,/",' ',$string); $string = preg_replace('/[\x80-\xff]{3}/', ' a ', $string); switch ($format) { case 1: preg_match_all(WORD_COUNT_MASK, $string, $matches); return $matches[0]; case 2: preg_match_all(WORD_COUNT_MASK, $string, $matches, PREG_OFFSET_CAPTURE); $result = array(); foreach ($matches[0] as $match) { $result[$match[1]] = $match[0]; } return $result; } return preg_match_all(WORD_COUNT_MASK, $string, $matches); } function mtw_wordcount() { global $page, $pages; if ( function_exists('str_word_count_utf8') ) { return str_word_count_utf8(strip_tags($pages[$page-1])); } else { return count(explode(" ",strip_tags($pages[$page-1]))); } } /* Auxilliary method. In case you want to use this somewhere outside the loop, where the $page and $pages globals don't necessarily work. Pass the string you want counted instead. */ function mtw_string_wordcount($instring) { if ( function_exists('str_word_count_utf8') ) { return str_word_count_utf8(strip_tags($instring)); } else { return count(explode(" ",strip_tags($instring))); } } ?> |
这样修改后,该插件就能在wp中正确统计中文字数。我的使用方法是:
1 | <?php the_content("本文共计".mtw_wordcount().'字,已浏览'.the_views("",false).'次。 继续阅读... »'); ?> |
其中的the_views("",false)部分是另一款插件WP-PostViews Plus实现的效果,不赘述。

mb_strlen
[Reply]
zhasm Reply:
January 2nd, 2009 at 11:12 am
经测试,mb_strlen函数返回的是字符串的绝对长度。当指定字符串编码为UTF-8时,每个中文字长度为1。例如,
$string="你好,世界。Hello world."
echo mb_strlen($string,"utf-8");
//此处结果为18.
echo str_word_count_utf8($string) //此处结果为6.
mb_strlen得到的是18=4个中文字+2个中文标点+10个英文字母+1空格+1点号,因此在wordpress中,不能依靠此函数来数中文字数与英语单词数之和。
[Reply]
学到了,非常感谢!
[Reply]
无论如何,空格是不应该计算在内的,全角空格也是。
可以改为:
$string = $string = preg_replace(“/~|!|`|·|#|¥|%|…|—|(|)|+|-|=|{|}|[|]|\\|||“|”|’|‘|;|:|《|》|〈|〉|、|?|。|,| |/”,’ ‘,$string);
[Reply]