2008年8月10日

有备无患:truncatehanzi - 按字数截取中文的 Django template filter

Django 自带的一个模板过滤器(Template Filter)truncatewords,可以按单词数截取字符串生成摘要。不过,truncatewords 只能用空格来分隔单词,对汉字就无能为力了。所以,我写了另一个模板过滤器 truncatehanzi,它通过 unicode 编码来区分西方字符和 CJK 汉字,对包括英语字母在内的西方字符以空格或其他符号来分隔并计算单词数,而对 CJK 汉字则是按字数计算。

使用方法和 truncatewords 一样,
{{ value|truncatehanzi:6 }}
如果 value 为“截取English、Γρεεκ等字母语言和CJK汉字。”,输出“截取English、Γρεεκ等字...”。

代码分为两个部分,截取汉字的脚本 truncate_hanzi.py 和生成过滤器的脚本 filters.py。

truncate_hanzi.py

 # -*- coding: UTF-8 -*-

import re
from django.utils.encoding import force_unicode
from django.utils.functional import allow_lazy

def truncate_hanzi(s, num):
    s = force_unicode(s)
    length = int(num)
    if length <= 0:
        return u'...'
    # Set up regex for alphanumeric characters
    # \u00c0-\u02af: Latin
    # \u0370-\u1fff: Greek and alphabet characters in other language
    re_alnum = re.compile(ur'[a-zA-Z0-9_\-\u00c0-\u02af\u0370-\u1fff]', re.U)
    # Set up regex for hanzi
    # \u3040-\ufaff: CJK characters
    re_hanzi = re.compile(ur'[\u3040-\ufaff]', re.U)
    hanzi = u''
    hanzi_len = 0
    word_temp = u''
    for char in s:
        # Check for alphabet characters
        if re_alnum.match(char):
            word_temp += char
            continue
        if word_temp:
            hanzi += word_temp
            hanzi_len += 1
            word_temp = ''
        # Check for length
        if hanzi_len >= length:
            if not hanzi.endswith('...'):
                hanzi += '...'
                break
        # Check for hanzi
        if re_hanzi.match(char):
            hanzi_len += 1
        hanzi += char
    hanzi += word_temp
    return hanzi
truncate_hanzi = allow_lazy(truncate_hanzi, unicode)

def demo():
    print truncate_hanzi('截取段落工具,支持English、Γρεεκ等字母语言和CJK汉字。', 6)
    print truncate_hanzi('截取段落工具,支持English、Γρεεκ等字母语言和CJK汉字。', 11)
    print truncate_hanzi('截取段落工具,支持English、Γρεεκ等字母语言和CJK汉字。', 20)

if __name__ == '__main__':
    demo()

filters.py

 # -*- coding: UTF-8 -*-
from django.template import Library
from django.template.defaultfilters import stringfilter

register = Library()

@stringfilter
def truncatehanzi(value, arg):
    """
    Truncates a string after a certain number of words including
    alphanumeric and CJK characters.

    Argument: Number of words to truncate after.
    """
    from truncate_hanzi import truncate_hanzi
    try:
        length = int(arg)
    except ValueError: # Invalid literal for int().
        return value # Fail silently.
    return truncate_hanzi(value, length)
truncatehanzi.is_safe = True

register.filter('truncatehanzi', truncatehanzi)

7 评论:

Zhang Le 说...

兄弟,我刚弄了个gentoo中文planet。我想把你的blog加入,不介意吧,;)

wyt 说...

很荣幸,:-)

匿名 说...

我的项目用到了这段代码,谢谢!

wyt 说...

欢迎使用:)

Leo Zhou 说...

用了这段代码,谢谢共享

wyt 说...

@Leo Zhou
欢迎使用:)
可以在这里找到最新版本
http://github.com/wuyuntao/truncate-hanzi/tree/master

Dan 说...

thanks

发表评论

欢迎留言

订阅我的博客

搜索我的博客

正在加载...

我的豆瓣广播

分享阅读

豆瓣秀

休斯敦火箭

我的文章归档

版权申明