Python 中文处理体验集 ::-- ZoomQuiet [2007-11-07 03:11:54]

CPUG联盟::

CPUG::门户plone

BPUG

SPUG

ZPUG

SpreadPython Python宣传

1. 中文.编码

1.1. 背景知识

1.2. 中文搜索/分词

1.3. Unicode处置

1.4. 体验集

1.4.1. 转换

1.4.2. 一般讲

{{{Oyster <[email protected]> reply-to [email protected], to "python-cn:CPyUG" <[email protected]>, date Nov 7, 2007 9:48 AM}}} subject [CPyUG:34634] python程序的编码-大家帮忙看看对不对

总结一下,看看对不对

  1. 源程序里面的汉字,直接用普通字符串的方式写出来 '汉字', 不要用unicode字符串的方式 u'汉字'
  2. 源程序保存为utf-8编码的文件,且文件头包含 #coding=utf-8 字眼。 其实,只要查找到了 "# coding 编码" 就行了,所以就算 乱写成encoding也无所谓。我个人喜欢

    # coding="utf-8" 因为它象一个合法的python赋值语句

  3. 要输出一个字符串或者已赋值的字符串变量,需要

    print unicode('汉字','utf-8') 糟糕的是,这里我们不能省略编码方式让其使用文件头指定的utf-8 因为我在py24上省略没有问题,但是py25就会报错

  4. 使用字符串作为函数调用的参数时,需要先转换为unicode对象
  5. unicode+str之后返回的就是unicode,所以print这样的值,不需要再次转换
  6. print类的实例(或者对实例使用str函数)的时候,调用的是__str__函数, 返回的也是str类型的对象。这样的话,会报错的 unicode(对象),首先查找的是__unicode__函数,并将其值作为返回值;如果找不到, 则使用__str__函数

  7. 如果变量是raw_input进来的,则该变量是一个str类型的对象,需要使用
    • a)unicode(变量,sys.stdin.encoding)

    或者
    • b)name.decode(sys.stdin.encoding)

    先转换为unicode对象
  8. 对于文件的io,应该使用codecs.open

测试用的很乱的代码

# coding='utf-8'
import locale
import sys

def hi(n2, name):
       return '%s, %s' % (n2,name)

name=raw_input('name>> ')
n2='你好'
print type(name), type(n2)
print hi(n2,name)
print hi(unicode(n2,'utf-8'),unicode(name,sys.stdin.encoding))
print hi(unicode(n2,'utf-8'),name.decode(sys.stdin.encoding))
print map(len, (unicode(n2,'utf-8'),name.decode(sys.stdin.encoding)))
print map(type,
(n2,name,unicode(n2,'utf-8'),unicode(name,sys.stdin.encoding)))
print map(type,(hi(n2,name),hi(unicode(n2,'utf-8'),unicode(name,
sys.stdin.encoding))))
print unicode(n2,'utf-8') + unicode(name,sys.stdin.encoding)


print sys.stdin.encoding, sys.stdout.encoding
print

def info(name, age=0):
       return "I'm %s, and %0i years old" % (name, age)

print '===1st test'

print unicode(info(unicode('张','utf-8'), 20))  #这里的输出是对的
print 'length=', len(unicode('张','utf-8'))     #长度计算也是对的
print

print '===2nd test'
name=raw_input('name>> ')#输入一个汉字,比如 李
print type(name)
print name, unicode(name,sys.stdin.encoding),
name.decode(sys.stdin.encoding)
print map(len,(name, unicode(name,sys.stdin.encoding),
name.decode(sys.stdin.encoding)))
print
unicode(name,sys.stdin.encoding)==name.decode(sys.stdin.encoding)
print info(name, 21)    #输出没有问题
print unicode(info(name, 21),sys.stdin.encoding)        #输出没有问题
print info(unicode(name,sys.stdin.encoding), 21)        #输出没有问题
print map(type, (info(name, 21),
info(unicode(name,sys.stdin.encoding), 21)))
print

print '===3rd test'
print type(name)        #是string
name2='李'
print type(name)        #还是string
print name==name2       #False?
print info(name, 21)    #输出没有问题
print 'length=', len(name)              #但是长度计算有问题
print


class human(object):
       def __init__(self, name, age=0):
               self.name=name
               self.age=age
       def __str__(self):
               print 'in __str__'
               return "I'm %s, and %0i years old" %(self.name,
self.age)
       def __unicode__(self):
               return "unistr: I'm %s, and %0i years old" %
(self.name,
self.age)

print '===4th test'
zhang=human(unicode('张','utf-8'),20)
print 'zhang.name=',zhang.name  #输出没有问题
print 'length=', len(zhang.name)        #长度没有问题

print unicode(zhang)  #输出没有问题
#print zhang    #出错!
#print str(zhang) #出错!
#print unicode(str(zhang)) #出错!

t=unicode(zhang)
import codecs
outfile = codecs.open("test.txt", "w", "utf-8")
outfile.write(t)
#outfile.write(t.decode('utf-8'))
#outfile.write(unicode('汉字','utf-8'))
outfile.close()

1.4.3. 通行思路

{{{realfun <[email protected]> reply-to [email protected], to [email protected], date Fri, Apr 18, 2008 at 6:05 PM subject [CPyUG:47963] python unicode 和 中文 (zz,不知道原作者了) }}}

python的中文问题一直是困扰新手的头疼问题,这篇文章将给你详细地讲解一下这方面的知识。当然,几乎可以确定的是,在将来的版本中,python会彻底解决此问题,不用我们这么麻烦了。

先来看看python的版本:

>>> import sys
>>> sys.version
'2.5.1 (r251:54863, Apr 18 2007, 08:51:08) [MSC v.1310 32 bit (Intel)]'

1.4.3.1. (一)原始尝试

用记事本创建一个文件ChineseTest.py,默认ANSI:

s = "中文"
print s

测试一下瞧瞧:

E:\Project\Python\Test>python ChineseTest.py
  File "ChineseTest.py", line 1
SyntaxError: Non-ASCII character '\xd6' in file ChineseTest.py on line 1, but no encoding declared; see http://www.pytho
n.org/peps/pep-0263.html for details

}偷偷地把文件编码改成UTF-8:

E:\Project\Python\Test>python ChineseTest.py
  File "ChineseTest.py", line 1
SyntaxError: Non-ASCII character '\xe4' in file ChineseTest.py on line 1, but no encoding declared; see http://www.pytho
n.org/peps/pep-0263.html for details

无济于事。。。 既然它提供了网址,那就看看吧。简单地浏览一下,终于知道如果文件里有非ASCII字符,需要在第一行或第二行指定编码声明。把ChineseTest.py文件的编码重新改为ANSI,并加上编码声明:

# coding=gbk
s = "中文"
print s

再试一下:

E:\Project\Python\Test>python ChineseTest.py
中文

正常咯:)

1.4.3.2. (二) 看一看它的长度

# coding=gbk
s = "中文"
print len(s)

结果:4

s这里是str类型,所以计算的时候一个中文相当于两个英文字符,因此长度为4。 我们这样写:

# coding=gbk
s = "中文"
s1 = u"中文"
s2 = unicode(s, "gbk") #省略参数将用python默认的ASCII来解码
s3 = s.decode("gbk") #把str转换成unicode是decode,unicode函数作用与之相同
print len(s1)
print len(s2)
print len(s3)

结果:

2
2
2

1.4.3.3. (三)

接着来看看文件的处理: 建立一个文件test.txt,文件格式用ANSI,内容为:

abc中文

用python来读取 {{{# coding=gbk print open("Test.txt").read() }}} 结果:abc中文

把文件格式改成UTF-8:

结果:abc涓枃

显然,这里需要解码:

# coding=gbk
import codecs
print open("Test.txt").read().decode("utf-8")
结果:abc中文

上面的test.txt我是用Editplus来编辑的,但当我用Windows自带的记事本编辑并存成UTF-8格式时, 运行时报错:

Traceback (most recent call last):
  File "ChineseTest.py", line 3, in <module>
    print open("Test.txt").read().decode("utf-8")
UnicodeEncodeError: 'gbk' codec can't encode character u'\ufeff' in position 0: illegal multibyte sequence

原来,某些软件,如notepad,在保存一个以UTF-8编码的文件时,会在文件开始的地方插入三个不可见的字符(0xEF 0xBB 0xBF,即BOM)。 因此我们在读取时需要自己去掉这些字符,python中的codecs module定义了这个常量:

# coding=gbk
import codecs
data = open("Test.txt").read()
if data[:3] == codecs.BOM_UTF8:
 data = data[3:]
print data.decode("utf-8")
结果:abc中文

1.4.3.4. (四)一点遗留问题

在第二部分中,我们用unicode函数和decode方法把str转换成unicode。为什么这两个函数的参数用"gbk"呢? 第一反应是我们的编码声明里用了gbk(# coding=gbk),但真是这样? 修改一下源文件:

# coding=utf-8
s = "中文"
print unicode(s, "utf-8")

运行,报错:

Traceback (most recent call last):
  File "ChineseTest.py", line 3, in <module>
    s = unicode(s, "utf-8")
UnicodeDecodeError: 'utf8' codec can't decode bytes in position 0-1: invalid data

显然,如果前面正常是因为两边都使用了gbk,那么这里我保持了两边utf-8一致,也应该正常,不至于报错。 更进一步的例子,如果我们这里转换仍然用gbk:

# coding=utf-8
s = "中文"
print unicode(s, "gbk")
结果:中文

翻阅了一篇英文资料,它大致讲解了python中的print原理:

简单地说,python中的print直接把字符串传递给操作系统,所以你需要把str解码成与操作系统一致的格式。Windows使用CP936(几乎与gbk相同),所以这里可以使用gbk。 最后测试:

# coding=utf-8
s = "中文"
print unicode(s, "cp936")
结果:中文

2. 反馈

PyInChinese (last edited 2009-12-25 07:14:49 by localhost)