何艳

何艳的博客

她的个人主页  她的博客

Python中文处理,完成功能的实用化

何艳  2009年08月31日 星期一 13:41 | 3047次浏览 | 5条评论

《可爱的Python》样章试读:这日,小白仅仅解决了一个问题——中文搜索问题;解决的尝试路径及相互关系如图 CDay-1-5所示。但是,实际上他获得了两大方面的进步: 1. 有了文本编码方面的知识。 2. 问题解决的方法论境界提高了一个层次,开始使用系统级别的解决方案了。 相对Python 方面,仅仅追加了一对内置函式和一个外部模块包使用的体验。 关键词: 编码 unicode chardet mount 注意:如果你使用M$ 系统,运气好的话是不会见到笔者列出的现象的,但是不保证以后遇不到自动处理下搞不定的光盘内容。希望那时候小白真的有个自由环境可以尝试其他方案。

本文摘自《可爱的Python》“光盘故事”CDay-1 实用化中文。

可爱的Python

CDay - 1 实用化中文

中文处理,完成功能的实用化

你碰到99%的问题,其他人之前已经遇到过了,所以,最佳的解决方式就是找到那段别人解决相似问题的代码!

回顾需求

小白已经实现的需求可以实现如下功能。

1. 可以扫描光盘内容,并存储为硬盘上的文本文件。

1)存储成*.cdc 的文本文件;

2)快速指定保存目录;

3)快速指定保存的文件名。

2. 可以根据储存到硬盘上的光盘信息进行搜索。

1)搜索指定目录中所有*.cdc文件;

2)指定关键字进行搜索;

3)列出所有含有关键字的信息行。

进一步尝试

回想起来,一直尝试搜索的都是英文关键字,中文的没有试过。

尝试来几下!……呜乎,什么也查不出来!

查阅记录文本

先来看看图CDay-1-1。

clip_image002

图CDay-1-1 mymusic-1.cdc内容

这种数据对吗?

当初为了简单,使用文档中的基本型,即:

#'cdctools.py' 中 cdWalker(cdrom,cdcfile) 的动作
...
for root, dirs, files in os.walk(cdrom):
export+="\n %s;%s;%s" % (root,dirs,files)
...

就是使用 os.walk() 的天然输出组织成每一行:

/media/cdrom0/EVA/Death-Rebirth;[];['eva8-01.Mp3', 'eva8-02.Mp3',...]
^                               ^ ^ ^
|                               | | +- files列表,此目录的文件名
|                               | +- 各个数据段使用";" 分隔
|                               +- dirs列表,子目录名,如果没有就为空
+- 当前目录

瞧着格式顶像,为什么到中文的地方就成了问号呢?

中文!永远的痛

不问不知道,一把辛酸泪啊!在网络中一搜索才知道,只要是个中国人,不论整什么开发,中文!永远会遇到各种问题的。不过,幸好比小白勤劳的人海了去,有关中文的Python 处理建议一搜一大堆。但是,有时候,选择太多也是个问题。

编码问题

clip_image004

图CDay-1-2 编码思维图谱

有行者给出如图CDay-1-2所示的思维图谱(Mind Map),目前还在理解过程中,先使用已知的方式测试本地硬盘文件的目录情况,如图 CDay-1-3所示。

clip_image006

图CDay-1-3 本地文件目录的测试结果

看着就不同,还得根据理解继续尝试,从而知道自己是否真正正确理解,另外一些测试结果如图CDay-1-4所示。

clip_image008

图CDay-1-4 另一些测试结果(使用unicode)

unicode(原始文本, 'utf8' ).encode('utf8')
文本 ==>decode()--> [unicode] ==>encode()--> utf-8文本
^       ^             ^         ^            ^
|       |             |         |            +- 最终的渴求
|       |             |         +- 此为编码过程;可以从unicode 输出为任意编码
|       |             +- Python 内置支持的unicode 格式数据
|       +- 此为解码过程,将已知编码的文本编译成宇宙通用的unicode数据
+- 原始文本信息,是什么编码你得知道!

也就是说文件没有编码之说,其实都是按二进制格式保存在硬盘中的,仅仅是在写入读取时须使用对应的编码进行处理,以便操作系统配合相关软件/字体,绘制到屏幕中给人看。所以关键问题是得知道原先这些字串数据是使用什么编码来编译的!但是在Unicode 之前都是使用类似对照表的形式来组织编码的,无法从串数据流本身统一解出不同的文字来。

只有猜!

猜编码函式一

def _smartcode(stream):
    try:
        ustring = unicode(stream, 'gbk')
    except UnicodeDecodeError:
        try:
            ustring = unicode(stream, 'big5')
        except UnicodeDecodeError:
            try:
                ustring = unicode(stream, 'shift_jis') 
            except UnicodeDecodeError: 
                try:
                    ustring = unicode(stream, 'ascii') 
                except:
                    return u"bad unicode encode!"

收集的音乐可不仅仅中文的,印度、伊朗等国的音乐都有可能收集,如果逐一去尝试,这个判定树就太可怕了!

升级!使用Python 的数据对象进行集成!

猜编码函式二

def _smartcode(stream):
    tryuni = ("gbk"
           ,"gb2312"
           ,"gb18030"
           ,"big5"
           ,"shift_jis"
           ,"iso2022_kr"
           ,"iso2022_jp"
           ,"ascii")
    try:
        for type in tryuni:
           try:
              ustring = unicode("%s}"%type+stream, type)
              #try decode by list
           except:
              continue
              #break!continue try decode guess
    except:
        return u"bad unicode encode!"

但是……

chardet

这么一项项猜,还是显得很傻,万一有些字的高位在不同编码中是相同的,那真的是只能撞大运了!尤其是对可怜的难兄难弟:gbk和big5。

比如:

>>> print '变巨'.decode('big5')

曹操

>>> print '变巨'.decode('gbk')

变巨

再问行者,他们给出个地址: http://chardet.feedparser.org/ ,上面有 Character encoding auto-detection (自动字符探测器)。

真的有呀! 而且是 Mozilla 使用的! 立用不疑!

怎么安装外部模块呢?软件包下载,解开压缩,嗯?没有INSTALL 说明文件,但是有个setup.py ,尝试执行一下。

-$1s-l
总用量为33。
drwxr-xr-x 3 zoomq zoomq 72 2008-04-29 11:25 build
drwx------ 2 zoomq zoomq 1264 2006-01-11 01:34 chardet
-rwx------ 1 zoomq zoomq 26432 2006-01-11 01:34 COPYING
drwxrwxrwx 4 zoomq zoomq 296 2006-01-11 01:34 docs
-rwx------ 1 zoomq zoomq 1981 2006-01-11 01:34 setup.py
~$ python setup.py
usage: setup.py [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] ...] 
   or: setup.py --help [cmd1 cmd2 ...]
   or: setup.py --help-commands
   or: setup.py cmd –help
error: no commands supplied
~$ sudo python setup.py install
running install
running build
running build_py
running install_lib
running install_egg_info
Removing /usr/lib/python2.5/site-packages/chardet-1.0.egg-info
Writing /usr/lib/python2.5/site-packages/chardet-1.0.egg-info

so easy! 好像使用了类似小白已经完成的交互式提醒呀!

看来所有Python 的软件都可以通过python setup.py install 进行安装!

1 import chardet
2 def _smartcode(stream):
3     """smart recove stream into UTF-8
4     """
5     ustring = stream
6     codedetect = chardet.detect(ustring)["encoding"]
7     print codedetect
8     try:
9          print ustring
10         ustring = unicode(ustring, codedetect)
11         print ustring
12         return "%s %s"%("",ustring.encode('utf8'))
13     except:
14         return u"bad unicode encode try!"

经过测试,已确信它在各种情况下都可以正确识别!但是不论怎么尝试,已经保存下来的.cdc文本依然是ASCII码!

另外的思路

也许真的就是 ASCII 码呢?

幸福的自由

冷静一下,既然,文件没有编码,都是二进制的,那么光盘文件是如何被系统认识的?!在列表中吼了一下,行者有点无奈地说:“TiosnG!”——There is one site named Google!好吧,小白老实地搜索了一番,发现了iso9660 ——所有光盘基本都是此文件格式的,同M$的 FAT32/ntfsGNU/Liunx 使用的 ext2/3、Unix使用的UFS...一样只是种文件系统。那么它必然是通过某种软件进行转换从而可以访问的。在 Ubuntu 中当然是标准地调用朴实强大的mount命令了。

~$ cat /etc/mtab
...
/dev/sda3 /dos vfat rw,utf8,umask=007,gid=46 0 0
...
/dev/sda1 /windows ntfs rw,nls=utf8,umask=007,gid=46 0 0
/dev/scd0 /media/cdrom0 iso9660 ro,noexec,nosuid,nodev,user=zoomq 0 0
...

观察默认的挂接光盘的行为和挂接Dos和Windows分区的情况,感觉是默认的挂接行为没有使用编码处理。那么通过改变挂接的行为,应该可以改善读取不到正确文本的情况。

#挂接成GBK
~$ sudo mount -o ro,norock,iocharset=cp936 /dev/scd0 /media/cdrom0
#挂接成UTF8
~$ sudo mount -o ro,norock,iocharset=utf8 /dev/scd0 /media/cdrom0

果然!果然!相对M$,系统安装成什么语言的系统,就永远使用该系统强行挂接光盘,好像八成应该不可以轻易按照你的意愿改变的……以前小白对于自由软件的认识仅仅是免费,难用,这下忽然间有所顿悟,不觉写下感慨:

自由软件好,我用我自在!

所谓自由,是基于对自个儿的了解,真正理解了自个儿想要什么之后,自由软件支持你的一切尝试!哈哈哈!

小白可以感受到这些,应该算是小灰了,可以稳定地向成熟的小黑——一名黑客挺进了!

提示:Hacker(黑客)绝对不是中国媒体中宣传的那些攻击他人电脑的家伙,黑客是些创造技术奇迹的单纯的人们( http://wiki.woodpecker.org.cn/moin/HackerHowto ,精巧地址: http://bit.ly/31rUuY )。被翻译所误指的那类家伙是Cracker(骇客)( http://en.wikipedia.org/wiki/Cracker ,精巧地址:http://bit.ly/3Xx0A),他是破坏者,未经授权而企图进入电脑系统者。这种入侵者通常会恶意进入他人的系统,而且有许多技巧可以破坏他人的系统。这个名词是骇客(Cracker)在1985年为对抗新闻媒体滥用hacker而提出的。1981~1982年前,曾有人推动使用“毛虫”代表Cracker,但并未成功。

改善数据结构

查询是可以了,但是,使用默认的列表打印格式来存储和汇报实在不咋的,想修改修改,于是

#cdctools.py...
def formatCDinfo(root,dirs,files):
    export = "\n"+root+"\n"
    for d in dirs:
        export+= "-d "+root+_smartcode(d)+"\n"
    for f in files:
        export+= "-f %s %s \n" % (root,_smartcode(f))
    export+= "="*70
        return export

存储下来的 .cdc 片段为:

...
-f /media/cdrom0/RyokoHirosue/Ryoko Hirosue-files.files title.gif
======================================================================
/media/cdrom0/RyokoHirosue/成长物语
-d /media/cdrom0/RyokoHirosue/成长物语 音乐极限--成长物语.files
-f /media/cdrom0/RyokoHirosue/成长物语 RH991101.mp3
-f /media/cdrom0/RyokoHirosue/成长物语 RH991102.mp3
d代表目录;f代表文件。它们分别是directory(目录)和file(文件)的缩写。

小结

这日,小白仅仅解决了一个问题——中文搜索问题;解决的尝试路径及相互关系如图 CDay-1-5所示。但是,实际上他获得了两大方面的进步:

1. 有了文本编码方面的知识。

2. 问题解决的方法论境界提高了一个层次,开始使用系统级别的解决方案了。

相对Python 方面,仅仅追加了一对内置函式和一个外部模块包使用的体验。

关键词:

编码

unicode

chardet

mount

注意:如果你使用M$ 系统,运气好的话是不会见到笔者列出的现象的,但是不保证以后遇不到自动处理下搞不定的光盘内容。希望那时候小白真的有个自由环境可以尝试其他方案。

提示:事实上存在Windows 下面的完全Unix环境,如Cygwin( http://www.cygwin.com ),它是一个通过运行于Windows下的免费的Unix子系统使用一个Dll(动态链接库)来实现的虚拟机,可以直接在 Windows 环境中使用各种Unix 实用工具。

clip_image018

图CDay-1-5 CDay-1问题解决思路图谱

练习

1. 自动判定你自个儿或是朋友的Blog 是什么编码的?

2. 如果是非utf-8 的,请编写小程序自动将指定文章转换成utf-8 编码保存。

 

------------------
本书即将上市,互动网预订: http://www.china-pub.com/195771
豆瓣讨论: http://www.douban.com/subject/3884108/

评论

我的评论:

发表评论

请 登录 后发表评论。还没有在Zeuux哲思注册吗?现在 注册 !
罗进

回复 罗进  2009年09月04日 星期五 09:37

刚买了,礼拜一就到了,期待

1条回复

何艳

回复 何艳  2009年09月02日 星期三 11:07

谢谢
互动网已经上架了^_^

1条回复

邓楠

回复 邓楠  2009年09月02日 星期三 07:14

期待这本书!

0条回复

暂时没有评论

Zeuux © 2024

京ICP备05028076号