Unicode 是一個(gè)系統(tǒng),用來(lái)表示世界上所有不同語(yǔ)言的字符。當(dāng) Python 解析一個(gè) XML 文檔時(shí),所有的數(shù)據(jù)都是以u(píng)nicode的形式保存在內(nèi)存中的。
一會(huì)兒你就會(huì)了解,但首先,先看一些背景知識(shí)。
歷史注解. 在 unicode 之前,對(duì)于每一種語(yǔ)言都存在獨(dú)立的字符編碼系統(tǒng),每個(gè)系統(tǒng)都使用相同的數(shù)字(0-255)來(lái)表示這種語(yǔ)言的字符。一些語(yǔ)言 (像俄語(yǔ)) 對(duì)于如何表示相同的字符還有幾種有沖突的標(biāo)準(zhǔn);另一些語(yǔ)言 (像日語(yǔ)) 擁有太多的字符,需要多個(gè)字符集。在系統(tǒng)之間進(jìn)行文檔交流是困難的,因?yàn)閷?duì)于一臺(tái)計(jì)算機(jī)來(lái)說(shuō),沒(méi)有方法可以識(shí)別出文檔的作者使用了哪種編碼模式;計(jì)算機(jī)看 到的只是數(shù)字,并且這些數(shù)字可以表示不同的東西。接著考慮到試圖將這些 (采用不同編碼的) 文檔存放到同一個(gè)地方 (比如在同一個(gè)數(shù)據(jù)庫(kù)表中);你需要在每段文本的旁邊保存字符的編碼,并且確保在傳遞文本的同時(shí)將編碼也進(jìn)行傳遞。接著考慮多語(yǔ)言文檔,即在同一文檔中使 用了不同語(yǔ)言的字符。(比較有代表性的是使用轉(zhuǎn)義符來(lái)進(jìn)行模式切換;噗,我們處于俄語(yǔ) koi8-r 模式,所以字符 241 表示這個(gè);噗,現(xiàn)在我們處于 Mac 希臘語(yǔ)模式,所以字符 241 表示其它什么。等等。) 這些就是 unicode 被設(shè)計(jì)出來(lái)要解決的問(wèn)題。
為了解決這些問(wèn)題,unicode 用一個(gè) 2 字節(jié)數(shù)字表示每個(gè)字符,從 0 到 65535。[8] 每個(gè) 2 字節(jié)數(shù)字表示至少在一種世界語(yǔ)言中使用的一個(gè)唯一字符。(在多種語(yǔ)言中都使用的字符具有相同的數(shù)字碼。) 這樣就確保每個(gè)字符一個(gè)數(shù)字,并且每個(gè)數(shù)字一個(gè)字符。Unicode 數(shù)據(jù)永遠(yuǎn)不會(huì)模棱兩可。
當(dāng)然,仍然還存在著所有那些遺留的編碼系統(tǒng)的情況。例如,7 位 ASCII,它可以將英文字符存諸為從 0 到 127 的數(shù)值。(65 是大寫(xiě)字母 “A”,97 是小寫(xiě)字母 “a”,等等。) 英語(yǔ)有著非常簡(jiǎn)單的字母表,所以它可以完全用 7 位 ASCII 來(lái)表示。像法語(yǔ)、西班牙語(yǔ)和德語(yǔ)之類(lèi)的西歐語(yǔ)言都使用叫做 ISO-8859-1 的編碼系統(tǒng) (也叫做“latin-1”),它使用 7 位 ASCII 字符表示從 0 到 127 的數(shù)字,但接著擴(kuò)展到了 128-255 的范圍來(lái)表示像 n 上帶有一個(gè)波浪線(241),和 u 上帶有兩個(gè)點(diǎn)(252)的字符。Unicode 在 0 到 127 上使用了同 7 位 ASCII 碼一樣的字符表,在 128 到 255上同 ISO-8859-1 一樣,接著使用剩余的數(shù)字,256 到 65535,擴(kuò)展到表示其它語(yǔ)言的字符。
在 處理 unicode 數(shù)據(jù)時(shí),在某些地方你可能需要將數(shù)據(jù)轉(zhuǎn)換回這些遺留編碼系統(tǒng)之一。例如,為了同其它一些計(jì)算機(jī)系統(tǒng)集成,這些系統(tǒng)期望它的數(shù)據(jù)使用一種特定的單字節(jié)編碼模 式,或?qū)?shù)據(jù)打印輸出到一個(gè)不識(shí)別 unicode 的終端或打印機(jī)。或?qū)?shù)據(jù)保存到一個(gè)明確指定編碼模式的 XML 文檔中。
在了解這個(gè)注解之后,讓我們回到 Python上來(lái)。
從 2.0 版開(kāi)始,Python 整個(gè)語(yǔ)言都已經(jīng)支持 unicode。XML 包使用 unicode 來(lái)保存所有解析了的 XML 數(shù)據(jù),而且你可以在任何地方使用 unicode。
>>> s = u'Dive in' >>> su'Dive in'>>> print s Dive in
>>> s = u'La Pe\xf1a' >>> print s Traceback (innermost last): File "<interactive input>", line 1, in ?UnicodeError: ASCII encoding error: ordinal not in range(128)>>> print s.encode('latin-1') La Peña
還記得我說(shuō)過(guò):需要從一個(gè) unicode 得到一個(gè)正常字符串時(shí),Python 通常默認(rèn)將 unicode 轉(zhuǎn)換成 ASCII 嗎?嗯,這個(gè)默認(rèn)編碼模式是一個(gè)可以定制的選項(xiàng)。
# sitecustomize.py # this file can be anywhere in your Python path,# but it usually goes in ${pythondir}/lib/site-packages/import syssys.setdefaultencoding('iso-8859-1')
>>> import sys>>> sys.getdefaultencoding() 'iso-8859-1'>>> s = u'La Pe\xf1a'>>> print s La Peña
如果你打算在你的 Python 代碼中保存非 ASCII 字符串,你需要在每個(gè)文件的頂端加入編碼聲明來(lái)指定每個(gè) .py 文件的編碼。這個(gè)聲明定義了 .py 文件的編碼為 UTF-8:
#!/usr/bin/env python# -*- coding: UTF-8 -*-
現(xiàn)在,想想 XML 中的編碼應(yīng)該是怎樣的呢?不錯(cuò),每一個(gè) XML 文檔都有指定的編碼。重復(fù)一下,ISO-8859-1 是西歐語(yǔ)言存放數(shù)據(jù)的流行編碼方式。KOI8-R 是俄語(yǔ)流行的編碼方式。編碼――如果指定了的話――都在 XML 文檔的首部。
<?xml version="1.0" encoding="koi8-r"?> <preface><title>Предисловие</title> </preface>
>>> from xml.dom import minidom>>> xmldoc = minidom.parse('russiansample.xml') >>> title = xmldoc.getElementsByTagName('title')[0].firstChild.data>>> title u'\u041f\u0440\u0435\u0434\u0438\u0441\u043b\u043e\u0432\u0438\u0435'>>> print title Traceback (innermost last): File "<interactive input>", line 1, in ?UnicodeError: ASCII encoding error: ordinal not in range(128)>>> convertedtitle = title.encode('koi8-r') >>> convertedtitle'\xf0\xd2\xc5\xc4\xc9\xd3\xcc\xcf\xd7\xc9\xc5'>>> print convertedtitle Предисловие
總結(jié)一下,如果你以前從沒(méi)有看到過(guò) unicode,倒是有些唬人,但是在 Python 處理 unicode 數(shù)據(jù)真是非常容易。如果你的 XML 文檔都是 7 位的 ASCII (像本章中的例子),你差不多永遠(yuǎn)都不用考慮 unicode。Python 在進(jìn)行解析時(shí)會(huì)將 XML 文檔中的 ASCII 數(shù)據(jù)轉(zhuǎn)換為 unicode,在任何需要的時(shí)候強(qiáng)制轉(zhuǎn)換回為 ASCII,你甚至永遠(yuǎn)都不用注意。但是如果你要處理其它語(yǔ)言的數(shù)據(jù),Python 已經(jīng)準(zhǔn)備好了。
Powered by: C++博客 Copyright © Hero