python 字符编码与解码——unicode、str和中文:UnicodeDecodeError: 'ascii' codec can't decode


摘要:在进行python脚本的编写时,如果我们用python来处理网页数据或者进行与中文字符有关的处理工作,经常出现这样的出错信息:SyntaxError: Non-ASCII character '\xe6' in file ./filename.py on line 3, but no encoding declared。本文主要讲解python中与unicode和中文、特殊字符编码有关的问题。字符编码和解码需要遵循什么规律?


前言:

       如果密码领域一样,从明文到密码是加密,从密码到明文是解密。在python中,编码:unicode-->str;解码str-->unicode.既然是编码,那么就和密码领域一样,编码和解码自然涉及到编码/解码方案(对应加密或者解密算法),unicode相当于明文。在python中,编码函数是encode(),解码函数是decode()。需要注意的一点是,如果我们调用str.encode(),这里涉及到一个隐士的类型转化,会现将str转化成unicode,才能进行编码,这也是不太容易理解的地方。所以,str.encode()实际上就等价于str.decode(sys.defaultencoding).encode().而sys.defaultencoding一般是ascii,它是不能用来编码中文字符的。

     在阅读本文之间,如果你对字符编码不是很熟悉,有必要先了解以下字符编码。可以参考:字符编码简介

1.一个中文字符编码问题


一个python脚本如下:

  #!/usr/bin/python
  
  string='我的'
  print string
运行脚本,提示信息如下:

SyntaxError: Non-ASCII character '\xe6' in file ./filename.py on line 3, but no encoding declared


出错原因:python默认采用ascii编码,而中文编码不再ascii编码能够表示的范围之内,所以string无法将“我的”作为ascii编码保存为str类型。


解决办法:采用中文字符编码,在脚本第二行加入编码类型,如下:

#!/usr/bin/python
#coding=gbk
string='我的'
print string

这里,coding同样可以采用utf-8等能够编码中文字符的模式。

2.python的对字符的编解码

字符编码/解码函数:

 1)unicode:这个是python的内建函数,位于unicode类。

unicode(string [, encoding[, errors]]) -> object

这个函数的作用是将string按照encoding的格式编码成为unicode对象。

省略参数将用python默认的ASCII来解码


2)decode:位于unicode类中。

 decode(...)
 |      S.decode([encoding[,errors]]) -> string or unicode

 |      
 |      Decodes S using the codec registered for encoding. 


#!/usr/bin/python
#coding=gbk
string='我的'
print string
s1=unicode(string,"gbk")
s2=string.decode("gbk")
print s1
print s2
这段代码的输出如下:
我的
鎴戠殑
鎴戠殑

显然,输出好像没有达到我们的期许的结果。为什么s1和s2输出的是乱码呢?string是str,print输出到屏幕,这个终端采用的字符编码有关。为什么string是正常的,而s1和s2都是乱码呢?我们接下来分析.

另外,你有没有觉得奇怪:为什么str类经过编码和解码以后的对象都是unicode呢?

答案:str.encode()实际上就等价于str.decode(sys.defaultencoding).encode().而sys.defaultencoding一般是ascii,它是不能用来编码中文字符的。

3)decode和encode都可以用于常规字符串和unicode字符串

但是:

     str.decode()和unicode.encode()是直接正规的使用。

     unicode.decode()会先将unicode转化成str,然后再执行decode()。

这里面涉及隐式类型转化的问题

3.codec是什么


Codec是把Coder/DECoder得首字母组合,它定义了文本跟二进制的转换方式,跟ASCII那种用一个字节把字符转换成数字的方式不同,Unicode用的是多字节,这导致了Unicode支持多种不同的编码方式,比如说codec支持的四种耳熟能详的编码方式是:ASCII,ISO8859—1/Latin-1,UTF-8,和UTF-16


最著名的是UTF-8编码,它也用一个字节来编码ASCII字符,这让那些必须同时处理ASCII码和Unicode码文本的程序员的工作变得非常轻松,因为ASCII字符的UTF-8编码和ASCII编码完全相同。


UTF-8编码可以用1到4个字节来表示其他语言的字符,这给那些需要直接处理Unicode数据的程序员带来了麻烦,因为他们没有办法按照固定长度逐一读出各个字符,幸运的是我们不需要掌握直接读取Unicode数据的方法,Python已经替我们完成了相关细节,我们无需为处理多字节字符的复杂问题而担心。

UTF-16也是一种变长编码,但是它不常用。


4.编码与解码

Unicode支持多种编码格式,这为程序员带来了额外的负担,每当你向一个文件写入字符串的时候,你必须定义一个编码用于把对应的Unicode内容转换成你定义的格式,Python通过Unicode字符串的encode()函数解决了这个问题,该函数接受字符串中的字符为参数,输出你指定的编码格式的内容。


所以,每次我们写一个Unicode字符串到磁盘上我们都要用指定的编码器给他“编码“一下,相应地,当我们从这个文件读取数据时,我们必须”解码”该文件,使之成为Unicode字符串对象。


5.python对unicode的支持


内建的unicode()函数:将一个string类型的字符串转变成一个unicode对象

decode/encode方法:用于将str对象转化成unicode对象,或者相反。

来看下面这一行例子:

#!/usr/bin/python
#coding=gbk
string='我的'
print "string is:",type(string)
print string

ustring=u"我的"
print "ustring is:",type(ustring)
print ustring

gbkstring=ustring.encode("gbk")
print "gbkstring is:",type(gbkstring)
print gbkstring

anotherstring=gbkstring.decode("gbk")
print "anotherstring is:",type(anotherstring)
print anotherstring


输出结果如下:


string is: <type 'str'>
我的
ustring is: <type 'unicode'>
鎴戠殑
gbkstring is: <type 'str'>
我的
anotherstring is: <type 'unicode'>
鎴戠殑


任何两种字符编码之间如果想完成转化,必须要通过unicode这个桥梁,先把它抓化成unicode对象;unicode对象直接进行输出,往往会出现乱码,需要解码成str对象。另外需要注意:unicode对象,gbk编码,ascii编码,str对象这四个不同的概念。注意区分什么是字符串类型,什么是编码类型。


6.注意事项


关于字符编码的原理,可以参考这里:

在python中需要使用unicode需要注意:


   1 程序中出现字符串时一定要加一个前缀u

   2 不要用str()函数,用Unicode()代替

   3 不要用过时的string模块。如果传给它非ASCII码,它会把一切搞砸。

   4 不到必须时不要在你的程序里编解码Unicode字符,只在你要写入文件或者数据库或者网络时,才调用encode()函数和decode()函数。

   5.使用什么字符编码,就要采用对应的字符集进行解码


内建的str()函数和chr()函数不能处理Unicode,它们只能处理常规ASCII编码的字符串,如果一个Unicode字符串作为参数传给了str()函数,它会首先被转换成ASCII码字符串然后交给str()函数。


7.关于linux终端的字符编码

终端等默认语言设置在/etc/environment之中,在linux下,如果terminal采用的是utf-8编码,那么如果我们的中文采用gbk编码,很有可能在输出到屏幕的时候产生乱码。

使用locale命令,可以查看与语言有关的环境变量:

hyk@hyk-linux:~/program/python/chapter6
$ locale
LANG=zh_CN.UTF-8
LANGUAGE=zh_CN:en_US:en
LC_CTYPE="zh_CN.UTF-8"
LC_NUMERIC=zh_CN.UTF-8
LC_TIME=zh_CN.UTF-8
LC_COLLATE="zh_CN.UTF-8"
LC_MONETARY=zh_CN.UTF-8
LC_MESSAGES="zh_CN.UTF-8"
LC_PAPER=zh_CN.UTF-8
LC_NAME=zh_CN.UTF-8
LC_ADDRESS=zh_CN.UTF-8
LC_TELEPHONE=zh_CN.UTF-8
LC_MEASUREMENT=zh_CN.UTF-8
LC_IDENTIFICATION=zh_CN.UTF-8
LC_ALL=

python的print方法,会自动将相关的字符编码,转化成该环境变量对应的字符编码,所以使用print 可能会出现乱码和报错;但是使用write却不会。


8.python中关于字符处理的出错与解决办法


问题一:

 13 strencode=string.encode("utf-8")
 14 print "strencode is : ",type(strencode)
 15 print strencode


UnicodeDecodeError: 'ascii' codec can't decode byte 0xe5 in position 4: ordinal not in range


解释:str本身是不能encode的,如果想要encode,先要转化成unicode,此时采用默认的ascii进行转化,所以就出错了。

解决办法:

1)指明str转化成unicode的编码方式:

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

     2)重置变量   sys .defaultencoding 

import sys   
reload(sys) # Python2.5 初始化后会删除 sys.setdefaultencoding 这个方法,我们需要重新载入   
sys.setdefaultencoding('utf-8')   
  
str = '中文'   
str.encode('gb18030')  


参考文献:

【1】字符编码简介:http://blog.csdn.net/trochiluses/article/details/8782019

  • 8
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
### 回答1: python3 unicodedecodeerror: 'ascii' codec can't decode byte 0xc4。 这个错误是因为Python3在处理字符串时,使用的默认编码ASCII。当遇到不是ASCII范围内的字符时,就会出现这个错误。 要解决这个问题,可以使用两种方法: 1. 在Python文件的开头添加以下代码,将默认编码设置为UTF-8: ``` # -*- coding: utf-8 -*- ``` 2. 在处理字符串时,使用显示的编码转换函数,将字符串转换为Unicode编码: ``` string = b"\xc4\x80\x80" decoded_string = string.decode("utf-8") ``` 这样就可以避免'ascii' codec can't decode byte 0xc4错误的出现。 ### 回答2: 这个错误是因为在Python 3中,默认的字符编码ASCII,而在处理某个字符串时,遇到了无法解码的字节序列(byte sequence),所以引发了`UnicodeDecodeError`异常。根据给出的错误信息`'ascii' codec can't decode byte 0xc4`,该字节序列为`\xc4`。 要解决这个问题,我们可以通过以下几种方法来进行处理: 1. 使用正确的编码格式解码:可以通过指定正确的编码格式来解码该字节序列。例如,如果该字节序列使用的是UTF-8编码,可以通过`decode('utf-8')`来解码,如:`string.decode('utf-8')`。 2. 忽略无法解码字符:可以通过在解码时设置错误处理标志(ignore)来忽略无法解码字符。例如,使用`decode('ascii', errors='ignore')`来忽略无法解码字符,如:`string.decode('ascii', errors='ignore')`。 3. 使用替代字符代替无法解码字符:可以通过在解码时设置错误处理标志(replace)来使用替代字符代替无法解码字符。例如,使用`decode('ascii', errors='replace')`来使用问号(?)替代无法解码字符,如:`string.decode('ascii', errors='replace')`。 4. 预先指定字符串的编码格式:在处理字符串之前,可以显式地指定字符串的编码格式。例如,如果字符串采用的是UTF-8编码,可以在字符串前面加上`u`前缀,如:`string = u"字符串"`。 需要根据具体情况选择合适的处理方法,以解决该编码错误。 ### 回答3: Python3的编码方式默认为ASCII,而当遇到无法识别的字符时就会报错。在你的情况中,报错是因为你尝试使用ASCII解码一个包含了0xc4字节的字符串。如果你想要解决这个问题,有以下两种方法: 1. 在字符串前加上"u",表示该字符串采用unicode编码。例如:s = u"\xc4"。这样,Python会知道如何正确地解码这个字符。 2. 在字符串前加上"b",表示该字符串采用字节编码。例如:s = b"\xc4"。这样,Python会将字符串作为字节序列处理,并不会尝试进行编解码。 需要注意的是,以上方法只是对于单个字符有效,如果是处理整个字符串,你可能需要采用其他方法,如使用正确的编码方式来解码。 另外,你也可以修改Python的默认编码方式来避免这个问题。这可以通过设置PYTHONIOENCODING环境变量来实现,例如: export PYTHONIOENCODING=utf-8 希望以上回答能帮到你解决问题。如果你有任何疑问,欢迎追问!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值