Maison  >  Article  >  développement back-end  >  À propos des problèmes d'encodage chinois en Python

À propos des problèmes d'encodage chinois en Python

零到壹度
零到壹度original
2018-04-16 11:38:501549parcourir

Le contenu de cet article concerne les problèmes de codage chinois en Python. Il a une certaine valeur de référence. Maintenant, je le partage avec vous. Les amis dans le besoin peuvent s'y référer

1. Problèmes d'encodage chinois en python

1.1 Encodage dans les fichiers .py

Les fichiers de script par défaut de Python sont tous codés en ANSCII, lorsqu'il y a des caractères dans le fichier qui ne sont pas dans la plage de codage ANSCII, vous devez utiliser les "instructions de codage" pour le corriger. Dans la définition d'un module, si le fichier .py contient des caractères chinois (à proprement parler, il contient des caractères non-anscii), vous devez préciser l'instruction d'encodage sur la première ou la deuxième ligne :

# -* - coding =utf-8 -*-or #coding=utf-8 D'autres encodages tels que : gbk, gb2312 sont également acceptables ; sinon un message similaire apparaîtra : SyntaxError : Caractère non-ASCII '/xe4' dans le fichier ChineseTest.py à la ligne 1, mais aucun encodage déclaré ; voir les informations d'exception telles que http://www.pytho pour plus de détails ;

Parlons d'abord des types de chaîne en python. Il existe deux types de chaîne en python, à savoir str et unicode. Ce sont deux classes dérivées de basestring. Le type str est un caractère qui contient des caractères représentés. (au moins) Une séquence d'octets de 8 bits ; chaque unité Unicode est un obj Unicode donc : la valeur len(u'China') est également 2 ; ;

Il y a cette phrase dans la documentation de str : Le type de données chaîne est également utilisé pour représenter des tableaux d'octets, par exemple pour contenir les données lues à partir d'un fichier. un fichier, ou lors de la lecture du contenu du réseau, l'objet géré est de type str ; si vous souhaitez convertir un str en un type d'encodage spécifique, vous devez convertir str en Unicode, puis convertir d'Unicode en un type d'encodage spécifique. tels que : utf-8, gb2312 etc. ;

Fonctions de conversion fournies en python :

unicode vers gb2312, utf-8, etc.

utf- 8, GBK en unicode en utilisant la fonction unicode (s,encoding) ou s.decode(encoding)

# -*- coding=UTF-8 -*-
if __name__ == '__main__': 
   s = u'中国'    
   s_gb = s.encode('gb2312')
Convertir une chaîne ordinaire en unicode

# -*- coding=UTF-8 -*-
if __name__ == '__main__':    s = u'中国'
    #s为unicode先转为utf-8
    s_utf8 =  s.encode('UTF-8')
    assert(s_utf8.decode('utf-8') == s)

Une exception se produira ici :
# -*- coding=UTF-8 -*-
if __name__ == '__main__':    s = '中国'
    su = u'中国''
    #s为unicode先转为utf-8
    #因为s为所在的.py(# -*- coding=UTF-8 -*-)编码为utf-8
    s_unicode =  s.decode('UTF-8')
    assert(s_unicode == su)
    #s转为gb2312,先转为unicode再转为gb2312
    s.decode('utf-8').encode('gb2312')
    #如果直接执行s.encode('gb2312')会发生什么?
    s.encode('gb2312')
 
# -*- coding=UTF-8 -*-
if __name__ == '__main__':    s = '中国'
    #如果直接执行s.encode('gb2312')会发生什么?
    s.encode('gb2312')

Python décodera automatiquement les s en Unicode d'abord, puis les encodera en gb2312. Étant donné que le décodage est effectué automatiquement par python et que nous ne spécifions pas la méthode de décodage, python utilisera la méthode spécifiée par sys.defaultencoding pour décoder. Dans de nombreux cas, sys.defaultencoding est ANSCII et une erreur se produira si s n'est pas de ce type.

Prenons la situation ci-dessus comme exemple. Mon sys.defaultencoding est ancii, et la méthode d'encodage de s est cohérente avec la méthode d'encodage du fichier, qui est utf8, donc une erreur s'est produite : UnicodeDecodeError : le codec 'ascii' peut 't décoder l'octet 0xe4 en position 0 : ordinal pas dans la plage (128)

Dans ce cas, nous avons deux façons de corriger l'erreur :

La première consiste à indiquer clairement la méthode d'encodage de s




La seconde consiste à remplacer sys.defaultencoding par la méthode d'encodage du fichier

#! /usr/bin/env python 
# -*- coding: utf-8 -*- 
s = '中文' 
s.decode('utf-8').encode('gb2312')



#! /usr/bin/env python 
# -*- coding: utf-8 -*- 
import sys 
reload(sys) # Python2.5 初始化后会删除 sys.setdefaultencoding 这个方法,我们需要重新载入 
sys.setdefaultencoding('utf-8') 
str = '中文' 
str.encode('gb2312')
Encodage du fichier et impression fonction

sont établies Un fichier test.txt, le format de fichier est ANSI, le contenu est :

abc chinois Utilisez python pour lire # coding=gbk
print open( "Test.txt").read()
Résultat : abc Chinois
Changez le format de fichier en UTF-8 :
Résultat : abc涓枃
Évidemment, un décodage est nécessaire ici :



Résultat :abc中文
J'ai utilisé Editplus pour modifier le test.txt ci-dessus, mais lorsque j'ai utilisé le Bloc-notes intégré de Windows pour le modifier et l'enregistrer au format UTF-8,

une erreur s'est produite lors de l'exécution :
# coding=gbk
import codecs
print open("Test.txt").read().decode("utf-8")



Il s'avère que certains logiciels, comme le bloc-notes, insèreront trois caractères invisibles (0xEF 0xBB 0xBF, ou BOM) au début du fichier lors de l'enregistrement d'un fichier codé en UTF-8.
Il faut donc supprimer nous-mêmes ces caractères lors de la lecture. Le module codecs en python définit cette constante :

Traceback (most recent call last):
  File "ChineseTest.py", line 3, in <module>
    print open("Test.txt").read().decode("utf-8")
UnicodeEncodeError: &#39;gbk&#39; codec can&#39;t encode character u&#39;/ufeff&#39; in position 0: illegal multibyte sequence


Résultat : abc chinois

# coding=gbk
import codecs
data = open("Test.txt").read()
if data[:3] == codecs.BOM_UTF8:
 data = data[3:]
print data.decode("utf-8")

(4) Quelques problèmes restants

Dans la deuxième partie, nous utilisons la fonction unicode et la méthode de décodage pour convertir str en unicode. Pourquoi les paramètres de ces deux fonctions utilisent-ils « gbk » ?

La première réaction est que nous utilisons gbk (# coding=gbk) dans notre instruction de codage, mais est-ce vraiment le cas ? Modifier le fichier source :


Exécuter, erreur :

# coding=utf-8
s = "中文"
print unicode(s, "utf-8")

Évidemment, si le précédent est normal car gbk est utilisé sur les deux côtés, alors ici j'ai conservé la cohérence UTF-8 des deux côtés, et cela devrait être normal sans provoquer d'erreur.
Un autre exemple, si on utilise encore gbk pour la conversion ici :

Traceback (most recent call last):
  File "ChineseTest.py", line 3, in <module>
    s = unicode(s, "utf-8")
UnicodeDecodeError: &#39;utf8&#39; codec can&#39;t decode bytes in position 0-1: invalid data


Résultat : Chinois

Principe de print en python :
# coding=utf-8
s = "中文"
print unicode(s, "gbk")
Quand Python exécute un print, il transmet simplement la sortie au système d'exploitation (en utilisant fwrite() ou quelque chose de similaire), et un autre programme est responsable de l'affichage de cette sortie à l'écran. Par exemple, sous Windows, il peut s'agir de la console Windows. sous-système qui affiche le résultat. Ou si vous utilisez Windows et exécutez Python sur une machine Unix ailleurs, votre client Windows SSH est en fait responsable de l'affichage des données. Si vous exécutez Python dans un xterm sous Unix, alors xterm et votre. Le serveur X gère l'affichage.

  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 = "中文"
rint unicode(s, "cp936")
# 结果:中文

这也可以解释为何如下输出不一致:

>>> s="哈哈"
>>> s&#39;
\xe5\x93\x88\xe5\x93\x88&#39;
>>> print s  #这里为啥就可以呢? 见上文对print的解释
哈哈>>> import sys
>>> sys.getdefaultencoding() &#39;
ascii&#39;
>>> print s.encode(&#39;utf8&#39;)  # s在encode之前系统默认按ascii模式把s解码为unicode,然后再encode为utf8
Traceback (most recent call last):
File "<stdin>", line 1, in ?
UnicodeDecodeError: &#39;ascii&#39; codec can&#39;t decode byte 0xe5 in position 0: ordinal not in range(128)
>>> print s.decode(&#39;utf-8&#39;).encode(&#39;utf8&#39;)
哈哈
>>>

编码问题测试

使用 chardet 可以很方便的实现字符串/文件的编码检测

例子如下:

>>>
 import
 urllib>>>
 rawdata = urllib.urlopen(&#39;http://www.google.cn/&#39;).read()>>>
 import
 chardet
>>>
 chardet.detect(rawdata){&#39;confidence&#39;: 0.98999999999999999, &#39;encoding&#39;: &#39;GB2312&#39;}>>>

chardet 下载地址 http://chardet.feedparser.org/

特别提示:

在工作中,经常遇到,读取一个文件,或者是从网页获取一个问题,明明看着是gb2312的编码,可是当使用decode转时,总是出错,这个时候,可以使用decode('gb18030')这个字符集来解决,如果还是有问题,这个时候,一定要注意,decode还有一个参数,比如,若要将某个String对象s从gbk内码转换为UTF-8,可以如下操作 
s.decode('gbk').encode('utf-8′) 
可是,在实际开发中,我发现,这种办法经常会出现异常: 
UnicodeDecodeError: ‘gbk' codec can't decode bytes in position 30664-30665: illegal multibyte sequence 
这 是因为遇到了非法字符——尤其是在某些用C/C++编写的程序中,全角空格往往有多种不同的实现方式,比如/xa3/xa0,或者/xa4/x57,这些 字符,看起来都是全角空格,但它们并不是“合法”的全角空格(真正的全角空格是/xa1/xa1),因此在转码的过程中出现了异常。 
这样的问题很让人头疼,因为只要字符串中出现了一个非法字符,整个字符串——有时候,就是整篇文章——就都无法转码。 
解决办法: 

s.decode(&#39;gbk&#39;, ‘ignore&#39;).encode(&#39;utf-8′)

因为decode的函数原型是decode([encoding], [errors='strict']),可以用第二个参数控制错误处理的策略,默认的参数就是strict,代表遇到非法字符时抛出异常; 
如果设置为ignore,则会忽略非法字符; 
如果设置为replace,则会用?取代非法字符; 
如果设置为xmlcharrefreplace,则使用XML的字符引用。 

python文档 

decode( [encoding[, errors]]) 
Decodes the string using the codec registered for encoding. encoding defaults to the default string encoding. errors may be given to set a different error handling scheme. The default is 'strict', meaning that encoding errors raise UnicodeError. Other possible values are 'ignore', 'replace' and any other name registered via codecs.register_error, see section 4.8.1. 
详细出处参考:http://www.jb51.net/article/16104.htm

参考文献

【1】Python编码转换

【2】全角半角转换的Python实现

【3】Python编码实现

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