天天看點

python 中文編碼1. 中文.編碼

http://wiki.woodpecker.org.cn/moin/PyInChinese

1. 中文.編碼

1.1. 背景知識

  • BPUG第15次.栖息谷文化傳播現場會課 Unicode 應用交流( AlexDong )

1.2. 中文搜尋/分詞

  • 庖丁分詞
  • IKAnalyzer和庖丁分詞性能對比
  • Lucene中文分詞器元件
  • IKAnalyzerNet釋出

1.3. Unicode處置

  • PythonicUnicode ~ 收集Python 的Unicode應用解說
    • 基于Unicode的Py 開發
    • CJK Unicode相關資料

1.4. 體驗集

1.4.1. 轉換

  • Python編碼處理集

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原理:

  • When Python executes a print statement, it simply passes the output to the operating system (using fwrite() or something like it), and some other program is responsible for actually displaying that output on the screen. For example, on Windows, it might be the Windows console subsystem that displays the result. Or if you're using Windows and running Python on a Unix box somewhere else, your Windows SSH client is actually responsible for displaying the data. If you are running Python in an xterm on Unix, then xterm and your X server handle the display.
  • To print data reliably, you must know the encoding that this display program expects.

簡單地說,python中的print直接把字元串傳遞給作業系統,是以你需要把str解碼成與作業系統一緻的格式。Windows使用CP936(幾乎與gbk相同),是以這裡可以使用gbk。 最後測試:

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