Python 언어에서 Uincode문자열 처리는 항상 혼란스러운 문제였습니다. 많은 Python 애호가들은 유니코드, UTF-8 및 기타 여러 인코딩 간의 차이점을 파악하는 데 어려움을 겪는 경우가 많습니다. 이 기사에서는 유니코드와 Python의 중국어 처리에 대한 관련 지식을 소개합니다. 아래 에디터로 살펴보겠습니다
파이썬 언어에서 유인코드 문자열 처리는 늘 혼란스러운 문제였습니다. 많은 Python 애호가들은 유니코드, UTF-8 및 기타 여러 인코딩 간의 차이점을 파악하는 데 어려움을 겪는 경우가 많습니다. 저자는 한때 이 "말썽꾸러기 집단"의 일원이었지만, 반년이 넘는 노력 끝에 마침내 몇 가지 관계를 알아냈습니다. 이제 다음과 같이 정리되어 모든 동료들과 공유됩니다. 동시에 나는 이 짧은 기사가 더 많은 실제 전문가들을 끌어들여 Python 중국어 환경을 공동으로 개선할 수 있기를 바랍니다.
본 글에서 언급된 다양한 의견 중 일부는 데이터를 참고하여 얻은 것이며, 일부는 저자가 기존의 다양한 코딩된 데이터를 이용하여 "추측 및 검증" 방법을 통해 얻은 것입니다. 글쓴이는 자신의 재능과 지식이 부족하다고 생각하는데, 그 속에 많은 실수가 숨겨져 있지 않을까 두렵습니다. 여러분 중에는 전문가가 많이 있습니다. 혹시 틀린 점을 발견하시면 제게 조언을 해주시기 바랍니다. 작성자가 스스로 당황하는 것은 작은 일이지만, 다른 사람이 잘못된 의견을 갖는 것은 큰 문제이므로 작성자의 얼굴에 대해 걱정할 필요가 없습니다.
섹션 1 텍스트 인코딩 및 유니코드 표준
유니코드 문자열을 설명하려면 먼저 유니코드 인코딩이 무엇인지부터 시작해야 합니다. 우리 모두 알고 있듯이 텍스트 디스플레이는 항상 컴퓨터 디스플레이 기능이 해결해야 하는 기본적인 문제였습니다. 컴퓨터는 실제로 텍스트를 일련의 "그림"으로 간주하며 각 "그림"은 문자에 해당합니다. 각 컴퓨터 프로그램은 텍스트를 표시할 때 "그림"이라는 텍스트가 표시되는 방식을 기록하는 "그림" 모음을 사용해야 하며, 각 문자의 "그림"에 해당하는 데이터를 찾아 같은 방식으로 단어를 "그려"야 합니다. . 이 "그림"을 "폰트"라고 하며, 기록된 글꼴 표시 데이터의 모음을 "문자 세트"라고 합니다. 프로그램 검색을 용이하게 하기 위해 각 문자의 글꼴 데이터는 문자 세트에서 순서대로 정렬되어야 하며 각 문자에는 고유 ID가 할당됩니다. 이 ID는 문자의 인코딩입니다. 컴퓨터가 문자 데이터를 처리할 때 이 인코딩은 항상 해당 문자가 나타내는 문자를 나타내는 데 사용됩니다. 따라서 문자 집합은 컴퓨터가 처리할 수 있는 문자 데이터 집합을 지정합니다. 분명히 국가마다 서로 다른 문자 세트 크기를 지정하고 해당 문자 인코딩도 다릅니다.
컴퓨터 역사상 가장 널리 사용되는 표준화된 문자 집합은 ASCII 문자 집합입니다. 이는 실제로 미국에서 공식화되고 북미 사용자를 위해 개발된 표준입니다. 7진수 비트 인코딩을 사용하며 128자를 표현할 수 있습니다. 이 문자 집합은 결국 ISO 조직에서 공식적으로 국제 표준으로 채택되었으며 다양한 컴퓨터 시스템에서 널리 사용됩니다. 요즘 모든 PC의 BIOS에는 ASCII 문자 집합의 글꼴 모델이 포함되어 있으며 이는 그 인기에서 분명합니다.
그러나 컴퓨터가 여러 나라에서 널리 보급되면서 ASCII 인코딩의 한계가 드러났습니다. 문자 공간이 정말 제한되어 있고 더 많은 문자를 수용할 수 없지만 대부분의 언어에서 사용해야 하는 문자 수는 128보다 훨씬 더 많습니다. 자국의 문자를 올바르게 처리하기 위해 여러 나라의 관료나 개인이 자체 문자 인코딩 세트를 설계하는 작업에 착수했으며, 결국 서양식 ISO-8859-1 인코딩과 같이 각 국가의 문자에 대한 많은 문자 인코딩이 등장했습니다. 유럽 문자에는 중국어 간체용 GB 시리즈 코드, 일본어용 SHIFT-JIS 코드 등이 있습니다. 동시에, 각각의 새로운 문자 세트가 원본 ASCII 텍스트와 호환되도록 하기 위해 대부분의 문자 세트는 변함없이 ASCII 문자를 처음 128자로 사용하고 해당 인코딩을 ASCII 인코딩과 일대일로 일치시킵니다.
이렇게 하면 다양한 국가에서 문자를 표시하는 문제가 해결되지만 문자가 왜곡된다는 새로운 문제도 발생합니다. 다양한 국가 및 지역에서 사용되는 문자 세트는 일반적으로 통일된 사양에 구속되지 않으므로 다양한 문자 세트의 인코딩이 서로 호환되지 않는 경우가 많습니다. 두 개의 서로 다른 문자 집합에서 동일한 단어의 인코딩은 일반적으로 다르며, 서로 다른 문자 집합에서 동일한 인코딩의 해당 문자도 다릅니다. A 인코딩으로 작성된 텍스트 조각은 B 인코딩만 지원하는 시스템에서 엉망인 문자로 표시되는 경우가 많습니다. 설상가상으로, 서로 다른 문자 집합에 사용되는 인코딩 길이는 종종 다릅니다. 단일 바이트 인코딩만 처리할 수 있는 프로그램은 더블 바이트 또는 심지어 다중 바이트 인코딩이 발생할 때 텍스트를 올바르게 처리하지 못하는 경우가 많습니다. " 문제. 이로 인해 이미 혼란스러웠던 상황이 더욱 혼란스러워졌습니다.
이러한 문제를 근본적으로 해결하기 위해 많은 대기업과 업계 단체가 공동으로 표준, 즉 유니코드를 제안했습니다. 유니코드는 실제로 새로운 문자 인코딩 시스템입니다. 2바이트 길이의 ID 번호로 문자 집합의 각 문자를 인코딩함으로써 최대 65536자를 수용할 수 있는 코딩 공간을 정의하고 오늘날 세계 여러 나라의 인코딩에 일반적으로 사용되는 모든 단어를 포함합니다. 인코딩 설계 시 신중한 고려를 통해 유니코드는 데이터 교환 시 다른 문자 집합으로 인해 발생하는 문자 왜곡 및 "반단어" 문제를 잘 해결했습니다. 동시에 유니코드 설계자들은 오늘날 많은 양의 글꼴 데이터가 여전히 다양한 국가에서 공식화한 다양한 인코딩을 사용하고 있다는 현실을 충분히 고려하여 "유니코드를 내부 인코딩으로 사용"하는 설계 개념을 제시했습니다. 즉, 문자 표시 프로그램은 여전히 원래 인코딩과 코드를 사용하고 응용 프로그램의 내부 논리는 유니코드를 사용합니다. 텍스트를 표시할 때 프로그램은 항상 유니코드로 인코딩된 문자열을 원래 인코딩으로 변환하여 표시합니다. 이런 방식으로 모든 사람이 유니코드를 사용하기 위해 글꼴 데이터 시스템을 다시 디자인할 필요가 없습니다. 동시에 여러 국가에서 공식화한 인코딩과 구별하기 위해 유니코드 설계자는 유니코드를 "와이드 문자 인코딩"(와이드 문자 인코딩)이라고 부르는 반면, 다양한 국가에서 공식화한 인코딩은 관례적으로 "멀티 문자 인코딩"이라고 합니다. -바이트 인코딩"(다중 바이트). 인코딩). 현재 유니코드 시스템은 4바이트 확장 인코딩을 도입했으며 점차적으로 ISO10646 인코딩 사양인 UCS-4로 통합되고 있습니다. 언젠가는 ISO10646 시스템을 사용하여 전 세계의 모든 텍스트 인코딩을 통합할 수 있기를 바랍니다. .
유니코드 시스템은 탄생하자마자 큰 기대를 받았고, ISO에서 인정하는 국제 표준으로 빠르게 받아들여졌습니다. 그러나 유니코드를 홍보하는 과정에서 유럽과 미국 사용자들의 반대에 부딪혔습니다. 반대하는 이유는 매우 간단합니다. 유럽과 미국 사용자가 사용하는 원래 인코딩은 1바이트 길이이고 더블바이트 유니코드 처리 엔진은 원래 1바이트 데이터를 처리할 수 없으며 기존의 모든 1바이트 텍스트가 필요한 경우입니다. 변환하려면 유니코드로 변환하려면 작업량이 너무 많을 것입니다. 또한 모든 단일 바이트 인코딩 텍스트가 더블 바이트 유니코드 인코딩으로 변환되면 모든 텍스트 데이터가 두 배의 공간을 차지하게 되며 모든 핸들러를 다시 작성해야 합니다. 그들은 이 비용을 받아들일 수 없습니다.
유니코드는 국제적으로 인정받는 표준임에도 불구하고, 표준화 기구가 가장 큰 컴퓨터 사용자 집단인 유럽과 미국 사용자들의 요구사항을 무시할 수는 없습니다. 그래서 모든 당사자 간의 협의 끝에 유니코드의 변형 버전인 UTF-8이 제작되었습니다. UTF-8은 멀티바이트 인코딩 시스템입니다.
1. UTF-8 인코딩은
첫 번째 영역은 단일 바이트 인코딩입니다.
인코딩 형식은 0xxxxxxx입니다.
은 유니코드에 해당합니다: 0x0000 - 0x007f
두 번째 영역은 더블바이트 인코딩입니다.
인코딩 형식은 다음과 같습니다. 110xxxxxx 10xxxxxx;
은 유니코드에 해당합니다. 0x0080 - 0x07ff
세 영역은 3바이트 인코딩이며
의 인코딩 형식은 1110xxxx 10xxxxxxx 10xxxxxx
은 유니코드에 해당합니다: 0x0800 - 0xffff
4개 영역은 4바이트 인코딩입니다.
인코딩 형식은 다음과 같습니다: 11110xxx 10xxxxxxx 10xxxxxx 10xxxxxx
해당 유니코드: 0x00010000 - 0x0001ffff
5개 영역은 5바이트 인코딩이며, 인코딩 형식은
is: 111110xx 10xxxxxxx 10xxxxxxx 10xxxxxxx 10xxxxxxx
해당 유니코드: 0x00200000 - 0x03ffffff
6개 영역은 6바이트 인코딩 > 에 해당합니다. 04000000 - 0x7fffffff
그 중 첫 번째, 두 번째, 세 번째 영역은 유니코드의 더블바이트 인코딩 영역에 해당하고, 네 번째 영역은 유니코드의 4바이트 확장 부분에 해당합니다(이에 따르면 정의에 따르면 UTF -8에도 5개와 6개의 구역이 있는데 GNU glibc 라이브러리에서 찾을 수 없었습니다. 이유는 모르겠습니다.) 5개와 6개가 순서대로 정렬되어 있으며 해당 위치의 문자는 그대로 유지됩니다. 유니코드와 동일 3. 표시할 수 없는 유니코드 문자는 0바이트로 인코딩됩니다. 즉, UTF-8에 포함되지 않습니다. 작성자가 GNU C 라이브러리 주석 에서 얻은 내용으로, UTF-8 인코딩 규칙에 따라 실제 상황과 일치하지 않을 수 있습니다. 첫 번째 영역의 128개 코드가 실제로 ASCII 코드라는 것을 찾는 것은 어렵지 않습니다. 따라서 UTF-8 처리 엔진은 ASCII 텍스트를 직접 처리할 수 있습니다. 그러나 UTF-8과 ASCII 인코딩의 호환성은 다른 인코딩을 희생하면서 발생합니다. 예를 들어 원래 중국어, 일본어, 한국어 문자는 기본적으로 2바이트 인코딩이었지만 유니코드 인코딩에서의 해당 위치는 UTF-8의 세 영역에 해당하고 각 문자 인코딩의 길이는 3바이트입니다. 즉, 중국, 일본, 한국에서 인코딩된 기존 비ASCII 문자 텍스트 데이터를 모두 UTF-8 인코딩으로 변환하면 크기가 원래 크기의 1.5배가 됩니다. 저자는 개인적으로 UTF-8의 인코딩 방식이 좀 불공평하다고 생각하지만, ASCII 텍스트에서 유니코드 세계로의 전환 문제를 해결해 폭넓은 인지도를 얻었습니다. 일반적인 예로는 XML과 Java가 있습니다. XML 텍스트의 기본 인코딩은 UTF-8이고 Java 소스 코드는 실제로 UTF-8 문자로 작성될 수 있습니다(JBuilder 사용자는 인상적일 것입니다). 오픈 소스 소프트웨어 세계에는 UTF-8 문자를 내부 인코딩으로 사용하는 잘 알려진 GTK 2.0도 있습니다. 너무 많이 이야기해서 주제가 다소 무리가 있는 것 같습니다. 많은 Python 애호가들은 "이것이 Python과 무슨 관련이 있는 걸까요?"라고 걱정하기 시작했을 것입니다. 파이썬의 세계로 오세요. 섹션 2 Python의 유니코드 인코딩 시스템 다국어 텍스트를 올바르게 처리하기 위해 Python은 버전 2.0 이후에 유니코드 문자열을 도입했습니다. 그 이후로 Python 언어의 문자열은 버전 2.0 이전에 오랫동안 사용되었던 기존 Python 문자열과 새로운 유니코드 문자열이라는 두 가지 유형으로 나누어졌습니다. Python 언어에서는 unicode() 내장 함수 를 사용하여 전통적인 Python 문자열을 "디코딩"하여 유니코드 문자열을 얻은 다음 유니코드 문자열의 encode() 메서드를 사용하여 이를 디코딩합니다. 유니코드 문자열. 문자열은 전통적인 Python 문자열로 "인코딩"되고 "인코딩"됩니다. 위 내용은 모든 Python 사용자에게 친숙해야 합니다. 그러나 Python의 유니코드 문자열이 진정한 "유니코드 인코딩 문자열"이 아니라 고유한 규칙을 따른다는 것을 알고 계셨습니까? 이 규칙의 내용은 매우 간단합니다. 1. ASCII 문자의 Python 유니코드 인코딩은 ASCII 인코딩과 동일합니다. 즉, Python 유니코드 문자열의 ASCII 텍스트는 여전히 단일 바이트 길이 인코딩입니다. 2 ASCII 문자 이외의 문자 인코딩은 유니코드입니다. 표준 인코딩의 2바이트(또는 4바이트) 인코딩입니다. (작가는 파이썬 커뮤니티가 이렇게 이상한 표준을 만든 이유가 ASCII 문자열의 보편성을 보장하기 위한 것이라고 추측합니다.) 보통 파이썬 응용 프로그램에서 유니코드 문자열은 다음과 같은 용도로 사용됩니다. 내부 처리, 터미널 표시 작업은 기존 Python 문자열로 완료됩니다(실제로 Python의 print 문은 2바이트 유니코드로 인코딩된 문자를 전혀 인쇄할 수 없습니다). Python 언어에서 전통적인 Python 문자열은 소위 "멀티바이트 인코딩된" 문자열로, 특정 문자 세트 인코딩(예: GB, BIG5, KOI8-R, JIS, ISO-8859-1 및 물론 UTF-8) 및 Python 유니코드 문자열은 특정 문자 세트 인코딩에서 "디코딩된" 유니코드 데이터를 나타내는 "와이드 문자 인코딩" 문자열입니다. 따라서 일반적으로 유니코드 인코딩이 필요한 Python 애플리케이션은 다음과 같은 방식으로 문자열 데이터를 처리합니다. us 예는 다음과 같습니다. 주어진: Red HatLinux환경에서 XWindow프로그래밍을 위해 PyGTK2를 자주 사용하는 Python 동료들은 이 상황을 오래 전에 발견했을 것입니다. 다음 명령문을 직접 작성하면: 이러한 명령문이 실행되면 터미널에 경고가 나타납니다. 그리고 프로그램 창 제목은 "Hello"로 설정되지 않습니다. 그러나 사용자가 중국어 코덱을 설치하고 위의 마지막 문장을 <🎜로 변경하면 >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)
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': 转换输入中出现无效字符序列
u_string = unicode('你好','gb2312')
main.set_title(u_string)
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
...
위에 제시한 예는 Linux의 PyGTK2에 대한 것이지만 비슷한 문제가 PyGTK에서만 나타나는 것은 아닙니다. PyGTK 외에도 PyQT, Tkinter 등과 같은 다양한 현재 Python 바인딩 그래픽 패키지는 유니코드 처리와 관련된 문제에 다소 직면하게 됩니다.
이제 Python의 유니코드 문자열 인코딩 메커니즘을 알아냈지만 우리가 가장 알고 싶은 질문은 여전히 해결되지 않았습니다. 중국어를 처리하기 위해 유니코드를 사용하여 Python 지원을 어떻게 만들 수 있습니까? 이 문제는 다음 섹션에서 설명하겠습니다.
섹션 3: Python의 유니코드 문자열이 중국어를 지원하도록 만드는 방법
이 섹션의 제목을 읽은 후 일부 Python 동료는 약간 반대할 수도 있습니다. 중국어를 처리하려면 유니코드를 사용해야 하나요? 우리는 보통 전통적인 Python 문자열을 잘 사용하지 않나요? "사실 일반적으로 문자열 연결 및 하위 문자열 일치와 같은 작업은 전통적인 Python 문자를 사용합니다. 꼬치면 충분합니다. 그러나 정규 표현식 다국적 문자를 포함하는 일치, 텍스트 편집, 표현식 분석 등과 같은 일부 고급 문자열 작업이 포함된 경우 이는 단일 바이트와 멀티바이트가 혼합된 대량의 문자열입니다. 전통적인 문자열 처리를 사용한다면 작업이 매우 번거로울 것입니다. 게다가 전통적인 문자열로는 "반 단어" 문제를 결코 해결할 수 없습니다. 그리고 유니코드를 사용할 수 있다면 이러한 문제는 쉽게 해결될 수 있습니다. 그러므로 우리는 중국어 유니코드 처리 문제를 직시하고 해결하기 위해 노력해야 합니다.
이전 섹션의 소개에서 우리는 Python의 유니코드 메커니즘을 사용하여 문자열을 처리하려는 경우 멀티바이트 중국어 인코딩(GB 인코딩 시리즈 및 BIG5 시리즈) 및 유니코드 인코딩/디코딩 모듈은 인코딩의 양방향 변환을 수행합니다. Python 용어에 따르면 이러한 인코딩/디코딩 모듈을 코덱이라고 합니다. 따라서 다음 질문은 다음과 같습니다. 이러한 코덱을 어떻게 작성합니까?
Python의 유니코드 메커니즘이 Python 코어에 하드 코딩되어 있는 경우 Python에 새 코덱을 추가하는 것은 힘든 작업이 될 것입니다. 다행스럽게도 Python의 설계자는 그렇게 어리석지 않습니다. Python에 새로운 코덱을 쉽게 추가할 수 있는 매우 확장 가능한 메커니즘을 제공합니다.
Python의 유니코드 처리 모듈에는 세 가지 가장 중요한 구성 요소가 있습니다. 하나는 codecs.py 파일, 다른 하나는 인코딩 디렉터리, 세 번째는 aliases.py 파일입니다. 처음 두 개는 Python 시스템 라이브러리의 설치 디렉터리에 있습니다(Win32 배포판인 경우 $PYTHON_HOME/lib/ 디렉터리에 있고 Red Hat Linux인 경우 /usr/lib/python에 있습니다). -version/ 디렉터리. 다른 시스템에서도 비슷하게 찾을 수 있습니다. 마지막 버전은 인코딩 디렉터리에 있습니다. 다음으로 이 세 가지를 각각 설명하겠습니다.
먼저 codecs.py 파일을 살펴보겠습니다. 이 파일은 표준 코덱 모듈이 가져야 하는 인터페이스를 정의합니다. 구체적인 내용은 여러분의 Python 배포판에서 찾을 수 있으므로 여기서는 자세히 다루지 않겠습니다. codecs.py 파일의 정의에 따르면 완전한 코덱에는 최소 3개의 클래스와 하나의 표준 기능이 있어야 합니다.
1 코덱 클래스
목적:
은 사용자가 전달한 버퍼 데이터(버퍼)를 기존 Python 문자열로 처리하고
해당 유니코드 문자열로 "디코딩"하는 데 사용됩니다. 완전한 코덱 클래스 정의는 Codec.decode() 및
Codec.encode()의 두 가지 메서드를 제공해야 합니다.
Codec.decode(input, <a href="http : //www.php.cn/wiki/222.html" target="_blank">errors<code>Codec.decode(input, <a href="http://www.php.cn/wiki/222.html" target="_blank">errors</a> = "strict")
= "strict")
는 입력 데이터를 전통적인 Python 문자열로 처리하는 데 사용됩니다. 해당 유니코드 문자열로 "디코딩"합니다.
매개변수:
입력: 입력 버퍼(문자열이거나 문자열 표현으로 변환될 수 있는 모든 객체일 수 있음)
오류: 변환 오류가 발생하는 경우 처리 옵션. 다음 세 가지 값 중에서 선택할 수 있습니다.
strict(기본값): 오류가 발생하면 UnicodeError 예외가 발생합니다.
replace: 오류가 발생하면 기본 유니코드 인코딩은 다음과 같습니다. ;
ignore: 오류가 발생하면 이 문자는 무시되고 나머지 문자에 대한 분석이 계속됩니다.
반환 값:
상수 목록(튜플): 첫 번째 요소는 변환된 유니코드 문자열이고 마지막 요소는 입력 데이터의 길이입니다.
Codec.encode(input, errors = "strict")
은 입력 데이터를 유니코드 문자열로 처리하고 이를 해당하는 기존 Python 문자열로 "인코딩"하는 데 사용됩니다.
매개변수:
input: 입력 버퍼(일반적으로 유니코드 문자열)
errors: 변환 오류 발생 시 처리 옵션입니다. 값 규칙은 Codec.decode() 메서드와 동일합니다.
반환 값:
상수 목록(튜플): 첫 번째 요소는 변환된 기존 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和香港扩展版本)。虽然同一派系的编码可以向下兼容,但考虑到其字符数目庞大,为了加快查找速度,笔者个人认为还是将它们分开编码比较合理。当然,如果能够找到对应字符集的转换公式,则这种分离就没有必要了;
위 내용은 유니코드와 파이썬 중국어 처리 방법에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!