wordpress UTF8 中文字数统计插件

January 2nd, 2009 Categories: 教程

最近想在博客中实现这样的功能:“本文字数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实现的效果,不赘述。

Tags: , , ,

4 Responses to “wordpress UTF8 中文字数统计插件”

  1. January 2nd, 2009 at 03:12
    1

    mb_strlen

    [Reply]

    zhasm Reply:

    经测试,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]

  2. March 13th, 2010 at 17:58
    2

    学到了,非常感谢!

    [Reply]

  3. March 13th, 2010 at 18:03
    3

    无论如何,空格是不应该计算在内的,全角空格也是。
    可以改为:
    $string = $string = preg_replace(“/~|!|`|·|#|¥|%|…|—|(|)|+|-|=|{|}|[|]|\\|||“|”|’|‘|;|:|《|》|〈|〉|、|?|。|,| |/”,’ ‘,$string);

    [Reply]

Leave a Comment