Maison >développement back-end >Tutoriel Python >Explication détaillée des méthodes de traitement chinoises Unicode et Python

Explication détaillée des méthodes de traitement chinoises Unicode et Python

高洛峰
高洛峰original
2017-03-20 09:06:561417parcourir

Dans le langage Python, le traitement Uincodestring a toujours été un problème déroutant. De nombreux passionnés de Python ont souvent du mal à comprendre les différences entre Unicode, UTF-8 et de nombreux autres encodages. Cet article présentera les connaissances pertinentes sur le traitement chinois Unicode et Python. Jetons un coup d'œil avec l'éditeur ci-dessous

Dans le langage Python, le traitement des chaînes Uincode a toujours été un problème déroutant. De nombreux passionnés de Python ont souvent du mal à comprendre les différences entre Unicode, UTF-8 et de nombreux autres encodages. L'auteur était autrefois membre de ce « groupe gênant », mais après plus de six mois de travail acharné, j'ai enfin compris certaines relations. Il est désormais organisé comme suit et partagé avec tous les collègues. Dans le même temps, j'espère également que ce court article pourra attirer davantage de vrais experts à se joindre et à améliorer conjointement notre environnement Python chinois.

Une partie des différentes opinions mentionnées dans cet article sont obtenues en consultant les données, et certaines sont obtenues par l'auteur à l'aide de diverses données codées existantes selon la méthode « deviner et vérifier ». L'auteur pense qu'il a peu de talent et de connaissances, et je crains qu'il ne cache de nombreuses erreurs. Il y a de nombreux experts parmi vous. Si l'un d'entre vous y trouve des erreurs, j'espère qu'il me donnera quelques conseils. C'est peu de chose pour l'auteur lui-même d'être embarrassé, mais c'est une grande affaire pour que les autres aient de fausses opinions, vous n'avez donc pas à vous soucier du visage de l'auteur.

Section 1 Encodage de texte et norme Unicode

Pour expliquer les chaînes Unicode, nous devons d'abord commencer par ce qu'est l'encodage Unicode. Comme nous le savons tous, l’affichage de texte a toujours été un problème fondamental que les fonctions d’affichage de l’ordinateur doivent résoudre. L'ordinateur n'est pas alphabétisé. Il considère en réalité le texte comme une série d'« images », chaque « image » correspondant à un personnage. Lorsque chaque programme informatique affiche du texte, il doit utiliser une collection d'« images » qui enregistre la façon dont l'« image » du texte est affichée, trouver les données correspondant à « l'image » pour chaque caractère et « dessiner » le mot de la même manière. .à l'écran. Cette « image » est appelée « police » et la collection de données d'affichage de police enregistrées est appelée « Jeu de caractères ». Afin de faciliter la recherche de programme, les données de police de chaque caractère doivent être disposées de manière ordonnée dans le jeu de caractères, et chaque caractère se verra attribuer un identifiant unique. Cet identifiant est l'encodage du caractère. Lorsque les ordinateurs traitent des données de caractères, cet encodage est toujours utilisé pour représenter le caractère qu'il représente. Par conséquent, un jeu de caractères spécifie un ensemble de données de caractères qu'un ordinateur peut traiter. Évidemment, différents pays spécifient différentes tailles de jeu de caractères, et les codages de caractères correspondants sont également différents.

Dans l'histoire des ordinateurs, le jeu de caractères standardisé le plus utilisé est le jeu de caractères ASCII. Il s’agit en fait d’une norme formulée aux États-Unis et développée pour les utilisateurs nord-américains. Il utilise un codage sur 7 bits binaires et peut représenter 128 caractères. Ce jeu de caractères a finalement été officiellement adopté par l'organisation ISO en tant que norme internationale et est largement utilisé dans divers systèmes informatiques. De nos jours, le BIOS de tous les PC contient le modèle de police du jeu de caractères ASCII, ce qui ressort de sa popularité.

Cependant, lorsque les ordinateurs se sont largement popularisés dans divers pays, les limites du codage ASCII ont été révélées : son espace de caractères est vraiment limité et ne peut pas accueillir plus de caractères, mais la plupart des langues doivent utiliser le nombre de caractères est bien plus que 128. Afin de gérer correctement leurs propres caractères, des fonctionnaires ou des particuliers de divers pays ont commencé à concevoir leurs propres jeux de codage de caractères, et finalement de nombreux codages de caractères ont vu le jour pour les caractères de chaque pays, tels que le codage ISO-8859-1 pour les caractères occidentaux. Caractères européens. Il existe des codes de la série GB pour le chinois simplifié et des codes SHIFT-JIS pour le japonais, etc. Dans le même temps, afin de garantir que chaque nouveau jeu de caractères est compatible avec le texte ASCII d'origine, la plupart des jeux de caractères utilisent invariablement des caractères ASCII comme leurs 128 premiers caractères et font correspondre leurs codages aux codages ASCII un à un.

De cette façon, le problème de l'affichage des caractères dans différents pays est résolu, mais cela amène également un nouveau problème : les caractères tronqués. Les jeux de caractères utilisés dans différents pays et régions ne sont généralement pas liés par des spécifications unifiées, de sorte que les codages des différents jeux de caractères sont souvent incompatibles les uns avec les autres. Le codage du même mot dans deux jeux de caractères différents est généralement différent et les caractères correspondants du même codage dans des jeux de caractères différents sont également différents. Un morceau de texte écrit avec l'encodage A sera souvent affiché sous la forme d'un fouillis de caractères sur un système qui ne prend en charge que l'encodage B. Pour aggraver les choses, les longueurs de codage utilisées par les différents jeux de caractères sont souvent différentes. Les programmes qui ne peuvent gérer que le codage sur un seul octet ne parviennent souvent pas à gérer correctement le texte lorsqu'ils rencontrent un codage sur deux octets ou même sur plusieurs octets. " problème. Cela a rendu la situation déjà chaotique encore plus confuse.

Afin de résoudre ces problèmes une fois pour toutes, de nombreuses grandes entreprises et organisations du secteur ont proposé conjointement une norme, qui est Unicode. Unicode est en fait un nouveau système de codage de caractères. Il code chaque caractère du jeu de caractères avec un numéro d'identification de deux octets, définissant ainsi un espace de codage pouvant accueillir jusqu'à 65 536 caractères et incluant tous les mots couramment utilisés dans les codages de divers pays du monde. Grâce à une réflexion approfondie lors de la conception du codage, Unicode a bien résolu les problèmes de caractères tronqués et de « demi-mots » causés par d'autres jeux de caractères dans l'échange de données. Dans le même temps, les concepteurs d'Unicode ont pleinement pris en compte le fait qu'une grande quantité de données de polices utilisent encore aujourd'hui divers encodages formulés par divers pays et ont proposé le concept de conception consistant à « utiliser Unicode comme encodage interne ». En d’autres termes, le programme d’affichage de caractères utilise toujours l’encodage et le code d’origine, et la logique interne de l’application utilisera Unicode. Lors de l'affichage de texte, le programme convertit toujours la chaîne codée Unicode en codage d'origine pour l'affichage. De cette façon, tout le monde n’a pas besoin de reconcevoir le système de données de polices pour utiliser Unicode. Dans le même temps, afin de le distinguer des codages formulés par différents pays, les concepteurs d'Unicode appellent Unicode « codages de caractères larges », tandis que les codages formulés par différents pays sont habituellement appelés « codages multi-octets » ( multi bypes). Aujourd'hui, le système Unicode a introduit un codage étendu sur quatre octets et converge progressivement avec UCS-4, qui est la spécification de codage ISO10646. On espère qu'un jour le système ISO10646 pourra être utilisé pour unifier tous les codages de texte dans le monde. .

Le système Unicode a suscité de grands espoirs dès sa naissance et a été rapidement accepté comme norme internationale reconnue par l'ISO. Cependant, au cours du processus de promotion d'Unicode, celui-ci s'est heurté à l'opposition des utilisateurs européens et américains. La raison de leur opposition est très simple : les codages originaux utilisés par les utilisateurs européens et américains sont longs sur un seul octet, et le moteur de traitement Unicode sur deux octets ne peut pas traiter les données originales sur un seul octet et si tous les textes existants sur un seul octet en ont besoin ; à convertir Pour le convertir en Unicode, la charge de travail sera trop importante. De plus, si tout le texte codé sur un octet était converti en codage Unicode sur deux octets, toutes leurs données texte occuperaient deux fois plus d'espace et tous les gestionnaires devraient être réécrits. Ils ne peuvent pas accepter cette dépense.

Bien qu'Unicode soit une norme internationalement reconnue, il est impossible pour l'organisme de normalisation d'ignorer les exigences des utilisateurs européens et américains, le plus grand groupe d'utilisateurs d'ordinateurs. Ainsi, après consultations entre toutes les parties, une variante d'Unicode a été produite, à savoir UTF-8. UTF-8 est un système de codage multi-octets. Ses règles de codage sont les suivantes :

1. Le codage UTF-8 est divisé en quatre zones :

La première zone est un encodage sur un seul octet,

le format d'encodage est : 0xxxxxxx ;

correspond à Unicode : 0x0000 - 0x007f ;

La deuxième zone est un encodage sur deux octets,

le format d'encodage est : 110xxxxx 10xxxxxx

correspond à Unicode : 0x0080 - 0x07ff

Les trois zones sont codées sur trois octets et le format de codage de

est : 1110xxxx 10xxxxxxx 10xxxxxx

correspond à Unicode : 0x0800 - 0xffff

Les quatre zones sont encodées sur quatre octets,

le format d'encodage est : 11110xxx 10xxxxxxx 10xxxxxx 10xxxxxx

correspond à Unicode : 0x00010000 - 0x0001ffff

Les cinq zones sont encodées sur cinq octets et le format d'encodage de

est : 111110xx 10xxxxxxx 10xxxxxxx 10xxxxxxx 10xxxxxxx

Unicode correspondant : 0x00200000 - 0x03ffffff

Les six zones sont codées sur six octets > Correspond à Unicode : 0x0400. 0000 - 0x7fffffffParmi elles, les première, deuxième et troisième zones correspondent à la zone de codage sur deux octets d'Unicode, tandis que la quatrième zone est pour la partie étendue sur quatre octets d'Unicode (selon cette définition, UTF -8 a aussi cinq et six districts, mais je ne les ai pas trouvés dans la bibliothèque GNU glibc, je ne sais pas pourquoi) ; Cinq et six sont disposés dans l'ordre, et les caractères aux positions correspondantes restent identique à Unicode ;

3. Les caractères Unicode qui ne peuvent pas être affichés sont codés sur 0 octet, en d'autres termes, ils ne sont pas inclus dans UTF-8 ( c'est la déclaration que l'auteur a obtenue de la bibliothèque GNU C

commentaire

, qui peut ne pas être cohérent avec la situation réelle selon les règles d'encodage UTF-8 ); Il ne nous est pas difficile de constater que les 128 codes de la première zone sont en réalité des codes ASCII. Ainsi, le moteur de traitement UTF-8 peut traiter directement le texte ASCII. Cependant, la compatibilité de l'UTF-8 avec le codage ASCII se fait au détriment des autres codages. Par exemple, à l'origine, les caractères chinois, japonais et coréens étaient essentiellement des codages sur deux octets, mais leurs positions dans le codage Unicode correspondent aux trois zones de l'UTF-8, et chaque codage de caractère fait trois octets. En d’autres termes, si nous convertissons toutes les données textuelles de caractères non ASCII existantes codées en Chine, au Japon et en Corée en codage UTF-8, leur taille deviendra 1,5 fois supérieure à la taille d’origine.

Bien que l'auteur pense personnellement que la méthode d'encodage UTF-8 semble un peu injuste, elle a résolu le problème de transition du texte ASCII vers le monde Unicode, elle a donc gagné une large reconnaissance. Des exemples typiques sont XML et Java : le codage par défaut du texte XML est UTF-8, et le code source Java peut en fait être écrit en caractères UTF-8 (les utilisateurs de JBuilder devraient être impressionnés). Il existe également le célèbre GTK 2.0 dans le monde des logiciels open source, qui utilise les caractères UTF-8 comme codage interne.

Cela dit, il semble que le sujet soit un peu tiré par les cheveux. De nombreux passionnés de Python ont peut-être commencé à s'inquiéter : "Qu'est-ce que cela a à voir avec Python ? D'accord, maintenant nous tournons notre attention ?" dans le monde de Python Come.

Section 2 Le système d'encodage Unicode de Python

Afin de gérer correctement le texte multilingue, Python a introduit les chaînes Unicode après la version 2.0. Depuis lors, les chaînes du langage Python ont été divisées en deux types : les chaînes Python traditionnelles, utilisées bien avant la version 2.0, et les nouvelles chaînes Unicode. Dans le langage Python, nous utilisons la fonction intégrée unicode() pour "décoder" une chaîne Python traditionnelle afin d'obtenir une chaîne Unicode, puis utilisons la méthode encode() de la chaîne Unicode pour décoder cette Chaîne Unicode La chaîne est "codée" et "codée" dans une chaîne Python traditionnelle. Le contenu ci-dessus doit être familier à chaque utilisateur Python. Mais saviez-vous que la chaîne Unicode de Python n'est pas une véritable « chaîne codée en Unicode », mais suit ses propres règles uniques. Le contenu de cette règle est très simple :

1. L'encodage Python Unicode des caractères ASCII est le même que leur encodage ASCII. En d'autres termes, le texte ASCII dans la chaîne Unicode de Python est toujours un codage d'une longueur d'un octet

2 Le codage des caractères autres que les caractères ASCII est Unicode ; Un codage sur deux octets (ou quatre octets) du codage standard. (L'auteur suppose que la raison pour laquelle la communauté Python a formulé une norme aussi étrange est peut-être pour garantir l'universalité des chaînes ASCII)

Habituellement dans les applications Python, les chaînes Unicode sont utilisées pour le traitement interne, tandis que le travail d'affichage du terminal est effectué par des chaînes Python traditionnelles (en fait, l'instruction print de Python ne peut pas du tout imprimer les caractères codés Unicode sur deux octets). Dans le langage Python, les chaînes Python traditionnelles sont dites « codées sur plusieurs octets », qui sont utilisées pour représenter diverses chaînes « codées » dans des codages de jeux de caractères spécifiques (tels que GB, BIG5, KOI8-R, JIS, ISO-8859-1, et bien sûr UTF-8) et les chaînes Python Unicode sont des chaînes de « codage de caractères larges », qui représentent des données Unicode « décodées » à partir d'un codage de jeu de caractères spécifique. Ainsi, généralement, une application Python qui doit utiliser le codage Unicode traitera souvent les données de chaîne de la manière suivante :


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)


Nous peut donner un exemple : les collègues Python qui utilisent souvent PyGTK2 pour la programmation XWindow dans l'environnement Red HatLinux ont peut-être découvert cette situation il y a longtemps : Si nous écrivons directement la déclaration suivante :


import pygtk
pygtk.require('2.0')
import gtk

main = gtk.Window() # create a window
main.set_title("你好") # NOTICE!


Lorsqu'une instruction comme celle-ci est exécutée, un avertissement comme celui-ci apparaîtra sur le terminal :

Error converting from UTF-8 to 'GB18030': 转换输入中出现无效字符序列

Et le titre de la fenêtre du programme ne sera pas défini sur "Bonjour" mais si l'utilisateur installe le codec chinois et modifie la dernière phrase ci-dessus par :


u_string = unicode('你好','gb2312')
main.set_title(u_string)


Ensuite, le titre de la fenêtre du programme sera correctement défini sur "Bonjour". Pourquoi est-ce ?

La raison est simple. La méthode gtk.Window.set_title() traite toujours la chaîne de titre qu'elle reçoit comme une chaîne Unicode. Lorsque le système PyGTK reçoit la requête main.set_title() de l'utilisateur, il traite la chaîne obtenue comme suit quelque part :


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
...


On voit que la chaîne title_unicode_string est "encodée" dans une nouvelle chaîne à l'intérieur du programme : real_title_string. Évidemment, cette real_title_string est une chaîne Python traditionnelle et son encodage est UTF-8. Dans la section précédente, l'auteur a mentionné que les chaînes utilisées en interne dans GTK2 sont codées en UTF-8, afin que le système principal de GTK2 puisse afficher correctement le titre après avoir reçu real_title_string.

Et si le titre saisi par l'utilisateur est une chaîne ASCII (par exemple : "hello world") ? Si l'on rappelle les règles de définition des chaînes Python Unicode, il n'est pas difficile de constater que si l'entrée de l'utilisateur est une chaîne ASCII, le résultat obtenu en la recodant est lui-même. En d'autres termes, si la valeur de title_unicode_string est une chaîne ASCII, les valeurs de real_title_string et title_unicode_string seront exactement les mêmes. Une chaîne ASCII est également une chaîne UTF-8, et il n'y aura aucun problème à la transmettre au système GTK2.

Les exemples que nous avons donnés ci-dessus concernent PyGTK2 sous Linux, mais des problèmes similaires n'apparaissent pas uniquement dans PyGTK. En plus de PyGTK, divers packages graphiques actuels liés à Python, tels que PyQT, Tkinter, etc., rencontreront plus ou moins des problèmes liés au traitement Unicode.

Maintenant que nous avons compris le mécanisme d'encodage de chaîne Unicode de Python, la question que nous voulons le plus savoir n'est toujours pas résolue : comment pouvons-nous prendre en charge Python en utilisant Unicode pour traiter le chinois ? Nous expliquerons ce problème dans la section suivante.

Section 3 : Comment faire en sorte que la chaîne Unicode de Python prenne en charge le chinois

Après avoir lu le titre de cette section, certains collègues de Python peuvent être un peu désapprobateurs : "Pourquoi faisons-nous devons-nous utiliser Unicode pour traiter le chinois ? Ne sommes-nous généralement pas doués pour utiliser les chaînes Python traditionnelles ? « En effet, en général, les opérations telles que la concaténation de chaînes et la correspondance de sous-chaînes utilisent des caractères Python traditionnels. Cependant, s'il s'agit d'opérations de chaîne avancées, telles que la correspondance d'expressions régulières contenant des caractères multinationaux, l'édition de texte, l'analyse d'expressions, etc., il s'agit d'un grand nombre de mélanges mono-octets et multi-octets. textes. L’opération serait très gênante si le traitement traditionnel des chaînes était utilisé. De plus, les cordes traditionnelles ne pourront jamais résoudre le foutu problème du « demi-mot ». Et si nous pouvons utiliser Unicode, ces problèmes peuvent être facilement résolus. Par conséquent, nous devons faire face et essayer de résoudre le problème du traitement Unicode chinois.

D'après l'introduction de la section précédente, nous savons que si vous souhaitez utiliser le mécanisme Unicode de Python pour traiter des chaînes, tant que vous disposez d'un code capable de combiner l'encodage chinois multi-octets (y compris les séries d'encodage GB et Série BIG5) et Unicode Le module d'encodage/décodage effectue une conversion bidirectionnelle de l'encodage. Selon la terminologie Python, un tel module d’encodage/décodage est appelé codec. La question suivante devient alors : Comment pouvons-nous écrire un tel codec ?

Si le mécanisme Unicode de Python est codé en dur dans le noyau Python, alors ajouter un nouveau codec à Python sera une tâche ardue. Heureusement, les concepteurs de Python ne sont pas si stupides qu’ils fournissent un mécanisme extrêmement extensible qui permet d’ajouter facilement de nouveaux codecs à Python.

Le module de traitement Unicode de Python comporte trois composants les plus importants : l'un est le fichier codecs.py, l'autre est le répertoire encodings et le troisième est le fichier aliases.py. Les deux premiers se trouvent dans le répertoire d'installation de la bibliothèque système Python (s'il s'agit d'une distribution Win32, elle se trouve dans le répertoire $PYTHON_HOME/lib/ ; s'il s'agit de Red Hat Linux, elle se trouve dans le répertoire /usr/lib/python -version/ (d'autres systèmes peuvent effectuer une recherche similaire), et le dernier se trouve dans le répertoire encodings. Ensuite, nous expliquons ces trois respectivement.

Jetons d'abord un coup d'œil au fichier codecs.py. Ce fichier définit l'interface que doit avoir un module Codec standard. Le contenu spécifique peut être trouvé dans votre propre distribution Python, je n'entrerai donc pas dans les détails ici. Selon la définition du fichier codecs.py, un codec complet doit avoir au moins trois classes et une fonction standard :

Classe Codec

.

Objectif :

est utilisé pour traiter les données du tampon (un tampon) transmises par l'utilisateur comme une chaîne Python traditionnelle et les "décoder"

dans la chaîne Unicode correspondante. Une définition complète de classe Codec doit fournir deux méthodes : Codec.decode() et

Codec.encode() :

Codec.decode(input, <a href="http%C2%A0:%20//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")

est utilisé pour traiter les données d'entrée comme une chaîne Python traditionnelle et "décodez-le" dans la chaîne Unicode correspondante.

Paramètres :

input : tampon d'entrée (peut être une chaîne ou tout objet pouvant être converti en une représentation sous forme de chaîne)

erreurs : lorsqu'une erreur de conversion se produit lors du traitement choix. Vous pouvez choisir parmi les trois valeurs suivantes :

strict (valeur par défaut) : si une erreur se produit, une exception UnicodeError est levée.

replace : si une erreur se produit, un encodage Unicode par défaut est généré ; sélectionné à la place. ;

ignorer : Si une erreur se produit, ce caractère est ignoré et l'analyse des caractères restants continue.

Valeur de retour :

Une liste constante (tuple) : le premier élément est la chaîne Unicode convertie et le dernier élément est la longueur des données d'entrée.

Codec.encode(input, errors = "strict")

est utilisé pour traiter les données d'entrée comme une chaîne Unicode et les "encoder" dans la chaîne Python traditionnelle correspondante.

Paramètres :

input : tampon d'entrée (généralement une chaîne Unicode)

erreurs : options de traitement lorsque des erreurs de conversion se produisent. Les règles de valeur sont les mêmes que celles de la méthode Codec.decode().

Valeur de retour :

Une liste constante (tuple) : le premier élément est la chaîne Python traditionnelle convertie et le dernier élément est la longueur des données d'entrée.

2. Classe StreamReader (doit généralement hériter de la classe 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, &#39;mycharset&#39;)

print my_unicode_string.encode(&#39;mycharset&#39;)


现在我们可以总结一下要编写一个新的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({/
&#39;mycodec&#39; : &#39;mycharset.mycodec&#39;,/
}}


以后每次要使用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和香港扩展版本)。虽然同一派系的编码可以向下兼容,但考虑到其字符数目庞大,为了加快查找速度,笔者个人认为还是将它们分开编码比较合理。当然,如果能够找到对应字符集的转换公式,则这种分离就没有必要了;

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn