在Python語言中,Uincode字串處理一直是個容易讓人迷惑的問題。許多Python愛好者經常因為搞不清Unicode、UTF-8還有其它許許多多的編碼之間的區別而大傷腦筋。本文將介紹Unicode和Python的中文處理的相關知識。下面跟著小編一起來看下吧
在Python語言中,Uincode字串處理一直是個容易讓人困惑的問題。許多Python愛好者經常因為搞不清Unicode、UTF-8還有其它許許多多的編碼之間的區別而大傷腦筋。筆者曾經也是這位「傷腦筋一族」的成員,但經過半年多的努力,現在終於初步弄清楚其中的一些關係。現將其整理如下,與各位同仁同享。同時也希望能藉這篇短文拋磚引玉,吸引更多真正的高手加入進來,共同完善我們的Python中文環境。
本文所提到的各種觀點,一部分是查閱資料所得,還有一部分是筆者利用已有各種編碼資料用「猜測加驗證」法得到。筆者自問才疏學淺,其中怕是藏有不少錯誤。各位看官中不乏高手,如果有哪一位發現其中哪裡有錯,萬望各位高人不吝賜教。筆者自己丟醜事小,觀點錯誤誤了別人事大,因此各位大可不必顧忌筆者的面子問題。
第一節 文字編碼和Unicode標準
要解釋Unicode字串就必須先從什麼是Unicode編碼開始說起。眾所周知,文字顯示一直是電腦顯示功能必須解決的基本問題。而電腦並不識字,它實際上是把文字看做是一串“圖片”,每張“圖片”對應一個字元。每個電腦程式在顯示文字時,必須藉助一個記錄這個文字“圖片”如何顯示的“圖片”集合,從中找到每一個字元對應“圖片”的數據,並依樣畫葫蘆地把這個字“畫”到螢幕上。這個“圖片”就被稱為“字模”,而記錄字模顯示資料的集合就被稱為“字元集”。為方便程式查找,每個字元的字模資料在字元集中必須是有序排列的,而且每個字元都會被分配一個獨一無二的ID,這個ID就是字元的編碼。而當電腦進行字元資料處理時,總是用這個編碼來代表它所表示的那個字元。因此,一個字元集就規定了一組電腦能夠處理的字元資料。顯然,不同國家指定的字元集大小不同,對應的字元編碼也不同。
在電腦歷史上,最廣泛使用的標準化字元集當首推ASCII字元集。它實際上是美國製訂的標準,針對北美用戶開發。它使用7個二進位位元編碼,可以表示128個字元。這個字符集最後被ISO組織正式採納為國際標準,並且大量應用在各種電腦系統上。現如今,所有PC機的BIOS中都內含了ASCII字元集的字模,其深入人心可見一斑。
但是,當電腦在各國大規模普及時,ASCII編碼的局限性就暴露出來了:它的字符空間實在有限,無法容納更多的字符,可是絕大多數語言需要使用的字數目都遠不止128個。為了能正確處理本國文字,各國官方或民間紛紛開始了設計本國文字編碼集的工作,並且最終湧現出許許多多針對各個國家文字的字符編碼,如針對西歐字符的ISO-8859-1編碼,簡體中文的GB系列編碼,還有日文的SHIFT-JIS編碼等等。同時,為了確保各個新的字符集能夠兼容原本的ASCII文本,大多數字符集不約而同地都將ASCII字符作為自己前128個字符,並使其編碼與ASCII編碼一一對應。
這樣一來,各國文字的顯示問題是解決了,可是又帶來一個新的問題:亂碼。不同國家、地區使用的字元集通常沒有統一的規範進行約束,因此各個字元集編碼往往互不相容。同一個字在兩個不同的字元集中編碼一般不同;而同一個編碼在不同的字元集中對應的字元也不一樣。一段用編碼A寫的文字在一個只支援編碼B的系統上往往會被顯示成一堆亂七八糟的字元。更糟的是,不同字元集使用的編碼長度往往也不相同,那些只能處理單字節編碼的程式在遇到雙位元組甚至是多位元組編碼的文字時,往往因為不能正確處理而產生了臭名昭著的「半個字」問題。這使得本來就已經混亂不堪的局面更是亂成了一團粥。
為了一勞永逸地解決這些問題,業界許多大公司和組織聯合提出了一個標準,這就是Unicode。 Unicode其實是一種新的字元編碼體系。它對字元集中的每個字元以兩個位元組長的ID號進行編碼,從而規定出一個可容納多達65536個字元的編碼空間,並且將現今國際上各國編碼中的常用字盡數收入罄中。由於在設計編碼時有了周全的考慮,Unicode很好地解決了其它字元集在進行資料交流時的亂碼和「半個字」問題。同時,Unicode的設計者充分考慮到現今大量字模資料使用的仍是各國製訂的各種編碼這一現實,提出了「將Unicode作為內部編碼」的設計理念。也就是說,字元顯示程式依然使用原先的編碼和程式碼,而應用程式的內部邏輯使用的將是Unicode。當要進行文字顯示時,程式總是將Unicode編碼的字串轉換成原本的編碼進行顯示。這樣,大家就不必為了使用Unicode而重新設計字模資料體係了。同時,為了與各國已經訂定的編碼相區別,Unicode的設計者將Unicode稱為「寬字元編碼」(wide characters encodings),而各國製訂的編碼習慣上被稱為「多位元組編碼」(multi bypes encodings)。時至今日,Unicode系統又引進了四位元組的擴展編碼,並且逐漸與與UCS-4,也就是ISO10646編碼規範合流,希望有朝一日能夠用ISO10646系統統一全世界所有的文字編碼。
Unicode體系甫一出世便被大家寄予厚望,並被迅速接受為ISO認可的國際標準。但是,Unicode在推廣過程中卻遭到了首先是歐美用戶的反對。他們反對的理由非常簡單:歐美用戶原本使用的編碼都是單字節長的,雙字節的Unicode處理引擎無法處理原本的單字節資料;而如果要把現有的單字節文字全部轉換成Unicode,工作量就太大了。再說,如果所有的單字節編碼文字都被轉換成雙位元組的Unicode編碼,他們所有的文字資料所佔用的空間都會變成原來的兩倍,而且所有的處理程序都要重新編寫。這個開銷他們無法接受。
雖然Unicode是國際認可的標準,但是標準化組織不可能不考慮歐美用戶這個最大的電腦使用群體的要求。於是在各方磋商之下,一個Unicode的變種版本產生了,這就是UTF-8。 UTF-8是一個多位元組的編碼體系,它的編碼規則如下:
#1、UTF-8編碼分為四個區:
#一區為單字節編碼,
#編碼格式為:0xxxxxxx;
對應Unicode:0x0000 - 0x007f
二區為雙位元組編碼,
編碼格式為:110xxxxx 10xxxxxx;
對應Unicode:0x0080 - 0x07ff
三區為三位元組編碼,
編碼格式為:1110xxxx 10xxxxxxx 10xxxxxx
#對應Unicode:0x0800 - 0xffff
四區為四位元組編碼,
#編碼格式為:11110xxx 10xxxxxxx 10xxxxxx 10xxxxxx
對應Unicode:0x0 0010000 - 0x0001ffff
五區為五字節編碼,
編碼格式為:111110xx 10xxxxxxx 10xxxxxxx 10xxxx 10xxxxxxx
對應Unicode:0x00200000 - 0x03ffffff
六區為六位元組編碼,
#編碼格式為:111110x 10xxxxxxx 10xxxxxxx 10xxxxxxx 10xxxxxxx 10xxxxxxx
#Unicode:0x04000000 - 0x7fffffffff
其中,一、二、三段編碼對應於整合的四位元組區則針對Unicode的四位元組擴展部分(依定義,UTF-8還有五區和六區,但筆者並未在GNU glibc庫中發現,不知為何);
2、各區依一、二、三、四、五、六順序排列,其對應位置上的字元與Unicode保持相同;
3.不可顯示的Unicode字元編碼為0字節,換言之,它們沒有被收入UTF-8(這是筆者從GNU C庫註釋中得到的說法,可能與實際情況不符);
#依照UTF-8編碼規則我們不難發現,其一區的128個編碼其實就是ASCII編碼。所以UTF-8的處理引擎可以直接處理ASCII文字。但是,UTF-8對ASCII編碼的相容是以犧牲其它編碼為代價的。例如,原本中、日、韓三國文字基本上都是雙位元組編碼,但它們在Unicode編碼中的位置對應到UTF-8中的三區,每個字元編碼要三個位元組長。換句話說,如果我們把所有現有的中、日、韓三國編碼的非ASCII字元文字資料轉換成UTF-8編碼,則其大小都會變成原來的1.5倍。
雖然筆者個人認為UTF-8的編碼方式顯得有些不夠公平,但畢竟它解決了ASCII文本到Unicode世界的過渡問題,所以還是贏得了廣泛的認可。典型的例子是XML和Java:XML文字的預設編碼就是UTF-8,而Java原始碼其實可以用UTF-8字元寫(JBuilder的使用者應該有印象)。另外還有開源軟體世界中大名鼎鼎的GTK 2.0,它使用UTF-8字元作為內部編碼。
說了這麼多,似乎話題有些扯遠了,許多Python愛好者可能已經開始著急:「這和Python有什麼關係呢?」好的,現在我們就把視線轉到Python的世界來。
第二節 Python的Unicode編碼系統
為了正確處理多語言文本,Python在2.0版後引入了Unicode字串。從那時起,Python語言中的字串就分為兩種:一種是2.0版之前就已經使用很久的傳統Python字串,一種則是新的Unicode字串。在Python語言中,我們使用unicode()內建函數對一個傳統Python字串進行“解碼”,得到一個Unicode字串,然後又透過Unicode字串的encode()方法對這個Unicode字串進行“編碼”,將其“編碼”成為傳統Python字串以上內容想必每個Python用戶都是爛熟於胸了。但你可知道,Python的Unicode字串並不是真正意義上的“Unicode編碼的字串”,而是遵循一種自己特有的規則。這個規則的內容簡單得很:
1、ASCII字元的Python Unicode編碼與它們的ASCII編碼相同。 也就是說,Python的Unicode字串中ASCII文字仍然是單字節長度編碼;
2、ASCII字元以外的字符,其編碼就是Unicode標準編碼的雙位元組(或四位元組)編碼。 (筆者猜想,之所以Python社群要製訂如此古怪的標準,可能是想保證ASCII字串的通用性吧)
通常在Python應用中,Unicode字串都是作為內部處理時使用,而終端顯示工作則由傳統的Python字串完成(實際上,Python的print語句根本無法列印出雙位元組的Unicode編碼字元)。在Python語言中,傳統Python字串就是所謂的「多位元組編碼」字串,用來表示各種被「編碼」成為具體字元集編碼的字串(例如GB、BIG5、KOI8-R、JIS、 ISO-8859-1,當然也有UTF-8);而Python Unicode字串則是「寬字元編碼」字串,表示從特定字元集編碼中「解碼」出來的Unicode資料。所以通常情況下,一個需要用到Unicode編碼的Python應用程式往往會以如下方式處理字串資料:
def foo(string, encoding = "gb2312"): # 1. convert multi-byte string to wide character string u_string = unicode(string, encoding) # 2. do something ... # 3. convert wide character string to printable multi-byte string return u_string.encode(encoding)
我們可以舉出一個例子:經常在Red Hat Linux環境中使用PyGTK2進行XWindow編程的Python同道可能早就發現過這樣的情況:如果我們直接寫出如下語句:
import pygtk pygtk.require('2.0') import gtk main = gtk.Window() # create a window main.set_title("你好") # NOTICE!
這樣的語句在執行時會在終端上出現這樣的警告:
Error converting from UTF-8 to 'GB18030': 轉換輸入中出現無效字元序列
且程式視窗標題不會被置為“你好」;但如果使用者安裝了中文的codec,並將上文的最後一句改為:
u_string = unicode('你好','gb2312') main.set_title(u_string)
則程式視窗標題將會被正確地設定為「你好」。這是為什麼呢?
原因很簡單。 gtk.Window.set_title()方法總是將自己接收的標題字串看做是一個Unicode字串。 PyGTK系統在接收到使用者的main.set_title()這項請求時,將得到的字串在某處做瞭如下處理:
class Window(gtk.Widget): ... def set_title(self, title_unicode_string): ... # NOTICE! unicode -> multi-byte utf-8 real_title_string = title_unicode_string.encode('utf-8') ... # pass read_title_string to GTK2 C API to draw the title ...
我们看到,字符串title_unicode_string在程序内部被“编码”成了一个新的字符串:real_title_string。显然,这个real_title_string是一个传统Python字符串,而它的编码用的是UTF-8。在上一节中笔者曾经提到过,GTK2的内部使用的字符串都是按UTF-8编码的,所以,GTK2核心系统在接收到real_title_string后可以正确显示出标题来。
那么,如果用户输入的标题是ASCII字符串(比如:“hello world”),又当如何?我们回想一下Python Unicode字符串的定义规则就不难发现,如果用户的输入是ASCII字符串,则对其进行重编码得到的就是其自身。也就是说,如果title_unicode_string的值是ASCII字符串,则real_title_string与title_unicode_string的值将完全一致。而一个ASCII字符串也就是一个UTF-8字符串,把它传递给GTK2系统不会有任何问题。
以上我们举的例子是关于Linux下的PyGTK2的,但类似的问题不仅出现在PyGTK中。除了PyGTK之外,现今各种Python绑定的图形包,如PyQT、Tkinter等,多多少少都会遇到与Unicode处理有关的问题。
现在我们弄清了Python的Unicode字符串编码机制,但是我们最想知道的问题还是没有解决:我们如何才能让Python支持用Unicode处理中文呢?这个问题我们将在下一节说明。
第三节 如何让Python的Unicode字符串支持中文
看完这一节的标题,有一些Python同道们可能会有些不以为然:“为什么一定要用Unicode处理中文呢?我们平时用传统Python字符串处理得不是也不错吗?”的确,其实在一般情况下像字符串连接、子串匹配等操作用传统Python字符串也就足够了。但是,如果涉及到一些高级的字符串操作,比如包含多国文字的正则表达式匹配、文本编辑、表达式分析等等,这些大量混杂了单字节和多字节文本的操作如果用传统字符串处理就非常麻烦了。再说,传统字符串始终无法解决那该死的“半个字”问题。而如果我们可以使用Unicode,则这些问题都可以迎刃而解。所以,我们必须正视并设法解决中文Unicode的处理问题。
由上一节的介绍我们知道,如果要想利用Python的Unicode机制处理字符串,只要能够拥有一个能够把多字节的中文编码(包括GB编码系列和BIG5系列)和Unicode编码进行双向转换的编码/解码模块就可以了。按照Python的术语,这样的编码/解码模块被称为codec。于是接下来的问题就变成了:我们该如何编写这样一个codec?
如果Python的Unicode机制是硬编码在Python核心中的话,那么给Python添加一个新的codec就将是一项艰苦卓绝的工作了。幸亏Python的设计者们没有那么傻,他们提供了一个扩充性极佳的机制,可以非常方便地为Python添加新的codecs。
Python的Unicode处理模块有三个最重要的组成部分:一是codecs.py文件,二是encodings目录,三是aliases.py文件。前两者都位于Python系统库的安装目录之中(如果是Win32发行版,就在$PYTHON_HOME/lib/目录下;如果是Red Hat Linux,就在/usr/lib/python-version/目录下,其它系统可以照此寻找),而最后一个则位于encodings目录下。接下来,我们分别对这三者加以说明。
先来看看codecs.py文件。这个文件定义了一个标准的Codec模块应有的接口。其具体内容大家可以在自己的Python发行版中找到,在此不再赘述。按照codecs.py文件的定义,一个完整的codec应该至少拥有三个类和一个标准函数:
1、Codec类
用途:
用于将用户传入的缓冲区数据(一个buffer)作为一个传统Python字符串,并将
其“解码”为对应的Unicode字符串。一个完整的Codec类定义必须提供Codec.decode()和
Codec.encode()两个方法:
Codec.decode(input, <a href="http://www.php.cn/wiki/222.html" target="_blank">errors</a> = "strict")
用于将输入的数据看做是传统Python字符串,并将其“解码”,转换成对应的Unicode字符串。
参数:
input:输入的buffer(可以是字符串,也可以是任何可以转换成字符串表示的对象)
errors:发生转换错误时的处理选择。可选择如下三种取值:
strict(默认值):如果发生错误,则抛出UnicodeError异常;
replace:如果发生错误,则选取一个默认的Unicode编码代替之;
ignore:如果发生错误,则忽略这个字符,并继续分析余下的字符。
返回值:
一个常数列表(tuple):首元素为转换后的Unicode字符串,尾元素为输入数据的长度。
Codec.encode(input, errors = "strict")
用于将输入的数据看做是Unicode字符串,并将其“编码”,转换成对应的传统Python字符串。
参数:
input:输入的buffer(通常就是Unicode字符串)
errors:发生转换错误时的处理选择。取值规则与Codec.decode()方法相同。
返回值:
一个常数列表(tuple):首元素为转换后的传统Python字符串,尾元素为输入数据的长度。
2、StreamReader类(通常应该继承自Codec类)
用于分析文件输入流。提供所有对文件对象的读取操作,如readline()方法等。
3、StreamWriter类(通常应该继承自Codec类)
用于分析文件输出流。提供所有对文件对象的写入操作,如writeline()方法等。
5、getregentry()函数
即“GET REGistry ENTRY”之意,用于获取各个Codec文件中定义的四个关键函数。其函数体统一为:
def getregentry(): return tuple(Codec().encode,Codec().decode,StreamReader,StreamWriter)
在以上提到的所有四个类中,实际上只有Codec类和getregentry()函数是必须提供的。必须提供前者是因为它是实际提供转换操作的模块;而后者则是Python系统获得Codec定义的标准接口,所以必须存在。至于StreamReader和StreamWriter,理论上应该可以通过继承codecs.py中的StreamReader和StreamWriter类,并使用它们的默认实现。当然,也有许多codec中将这两个类进行了改写,以实现一些特殊的定制功能。
接下来我们再说说encodings目录。顾名思义,encodings目录就是Python系统默认的存放所有已经安装的codec的地方。我们可以在这里找到所有Python发行版自带的codecs。习惯上,每一个新的codec都会将自己安装在这里。需要注意的是,Python系统其实并不要求所有的codec都必须安装于此。用户可以将新的codec放在任何自己喜欢的位置,只要Python系统的搜索路径可以找得到就行。
仅仅将自己写的codec安装在Python能够找到的路径中还不够。要想让Python系统能找到对应的codec,还必须在Python中对其进行注册。要想注册一个新的codec,就必须用到encodings目录下的aliases.py文件。这个文件中只定义了一个哈希表aliases,它的每个键对应着每一个codec在使用时的名称,也就是unicode()内建函数的第二个参数值;而每个键对应的值则是一个字符串,它是这个codec对应的那个处理文件的模块名。比如,Python默认的解析UTF-8的codec是utf_8.py,它存放在encodings子目录下,则aliases哈希表中就有一项表示其对应关系:
'utf-8' : 'utf_8', # the <a href="http://www.php.cn/code/8212.html" target="_blank">module</a> `utf_8' is the codec <a href="http://www.php.cn/wiki/125.html" target="_blank">for</a> UTF-8
同理,如果我们新写了一个解析‘mycharset'字符集的codec,假设其编码文件为mycodec.py,存放在$PYTHON_HOME/lib/site-packages/mycharset/目录下,则我们就必须在aliases哈希表中加入这么一行:
'mycharset' : 'mycharset.mycodec',
这里不必写出mycodec.py的全路径名,因为site-packages目录通常都在Python系统的搜索路径之中。
Python解释器在需要分析Unicode字符串时,会自动加载encodings目录下的这个aliases.py文件。如果mycharset已经在系统中注册过,则我们就可以像使用其它内建的编码那样使用我们自己定义的codec了。比如,如果按照上面的方式注册了mycodec.py,则我们就可以这样写:
my_unicode_string = unicode(a_multi_byte_string, 'mycharset') print my_unicode_string.encode('mycharset')
现在我们可以总结一下要编写一个新的codec一共需要那些步骤:
首先,我们需要编写一个自己的codec编码/解码模块;
其次,我们要把这个模块文件放在一个Python解释器可以找到的地方;
最后,我们要在encodings/aliases.py文件中对其进行注册。
从理论上说,有了这三步,我们就可以将自己的codec安装到系统中去了。不过这样还不算完,还有一个小问题。有时候,我们出于种种原因,不希望随便修改自己的系统文件(比如,一个用户工作在一个集中式的系统中,系统管理员不允许别人对系统文件进行修改)。在以上介绍的步骤中,我们需要修改aliases.py文件的内容,这是一个系统文件。可如果我们不能修改它,难道我们就不能添加新的codec吗?不,我们当然有办法。
这个办法就是:在运行时修改encodings.aliases.aliases哈希表的内容。
还是使用上面那个假设,如果用户工作系统的管理员不允许用户把mycodec.py的注册信息写入aliases.py,那么我们就可以如此处理:
1、将mycodec.py放在一个目录下,比如/home/myname/mycharset/目录;
2、这样编写/home/myname/mycharset/init.py文件:
import encodings.aliases # update aliases hash map encodings.aliases.aliases.update({/ 'mycodec' : 'mycharset.mycodec',/ }}
以后每次要使用Python时,我们可以将/home/myname/加入搜索路径,并且在使用自己的codec时预先执行:
import mycharset # execute the script in mycharset/init.py
这样我们就可以在不改动原有系统文件的情况下使用新的codecs了。另外,如果借助Python的site机制,我们还可以让这个import工作自动化。如果大家不知道什么是site,就请在自己的Python交互环境中运行:
import site print site.doc
浏览一下site模块的文档,即可明白个中技巧。如果大家手头有Red Hat Linux v8,v9,还可以参考一下Red Hat的Python发行版中附带的日文codec,看看它是如何实现自动加载的。也许不少同道可能找不到这个日文的codec在哪里,这里列出如下:
Red Hat Linux v8:在/usr/lib/python2.2/site-package/japanese/目录下; Red Hat Linux v9:在/usr/lib/python2.2/lib-dynload/japanese/目录下;
提示:请Red Hat用户注意site-packages目录下的japanese.pth文件,结合site模块的文档,相信马上就能豁然开朗。
结束语
记得当初笔者在Dohao论坛上夸下海口:“如果可以的话,我可以为大家编写一个(中文模块)”,现在回想起来,不禁为自己当初的不知天高地厚而汗颜。一个把自己所有的的时间都花在学习上,一个学期只学七门课程,还落得个两门课不及格的傻瓜研究生,哪里有什么资格在大家面前如此嚣张。现如今,第二个学期由于这两门课的缘故负担陡增(十门课呀!),家中老父老母还眼巴巴地等着自己的儿子能给他们挣脸。要想在有限的时间之内,既保证学习,又保证工作(我要承担导师的课程辅导工作,同时还有一个学校的教学改革方案需要我在其中挑大梁),已经是疲于应付,再加上一个中文模块……唉,请恕笔者分身乏术,不得不食言。
因此,笔者斗胆,在此和盘托出自己这半年以来的心得,只希望能够找到一批,不,哪怕是一个也好,只要是对这个项目感兴趣的同道中人,能够接下笔者已经整理出来的知识,把一个完整的(至少应该包含GB、BIG5、笔者个人认为甚至还应包括HZ码)中文模块编写出来,贡献给大家(不论是有偿的还是无偿的),那就是我们广大Python爱好者之福了。另外,Python的发行版至今尚未包括任何中文支持模块。既然我等平日深爱Python,如果我们的工作能因此为Python的发展做出一点贡献,何乐而不为呢?
附录 几个小小提示
1、LUO Jian兄已经编写了一个非常不错的中文模块(Dohao上有链接,文件名是showfile.zip,这个模块比我已经写完的草稿版本要快得多),同时支持GB2312和GB18030编码,可惜不支持BIG5。如果大家有兴趣,可以下载这个模块研究一下;
2、和其它字符集编码相比,中文模块有其特殊性,那就是其海量的字符数目。一些相对较小的字符集还好说,比如GB2312,可以利用哈希表查找。而对于巨大的GB18030编码,如果简单地将所有数据制成一个特大的编码对照表,则查询速度会慢得让人无法容忍(笔者在编写模块时最头疼的就是这一点)。如果要编写一个速度上能让人满意的codec,就必须考虑设计某种公式,能够通过简单地运算从一种编码推算出另一种来,或者至少能推算出它的大概范围。这就要求程序员要能对整个编码方案做统计,设法找到规律。笔者认为,这应该是编写中文模块时的最大难点。或许是数学功底实在太差的缘故,笔者费尽心机也未能找出一个规律来。希望能有数学高手不吝赐教;
3、中文編碼分為兩大派系:GB和BIG5。其中GB又分為GB2312、GBK和、GB18030三種編碼,而BIG5也分為BIG5和BIG5-HKSCS兩種(分別對應原始的BIG5和香港擴充版本)。雖然同一派系的編碼可以向下相容,但考慮到其字元數目龐大,為了加快查找速度,筆者個人認為還是將它們分開編碼比較合理。當然,如果能夠找到對應字元集的轉換公式,則這種分離就沒有必要了;
【相關推薦】
1. 特別推薦#:「php程式設計師工具箱」V0.1版本下載
2. Python免費影片教學
以上是詳解Python中Unicode和utf-8的詳細內容。更多資訊請關注PHP中文網其他相關文章!