一文读懂ascii,unicode, utf-8,彻底解决UnicodeEncodeError的问题

1. ASCII

在计算机里,一切都是用二进制存储的,比如 a 这个字母,在计算机里,用 0110 0001 这个8个bit来表示,8个bit就是一个字节。所谓ascii,就是一个字符编码,它规定了英文中的各种字符在计算机里表示形式。

ascii码作为一种字符编码,可以表示128个字符与二进制之间的关系,字符a的二进制编码是“0110 0001”,把这个二进制转成10进制就是97,下面的代码可以处理这种关系的转换

en_str = 'a'
en_ascii = ord(en_str)
print(en_ascii, type(en_ascii))

print(chr(97))


输出结果

97 <class 'int'>
a

2. unicode


2.1 大一统

只要稍微一思考,就会发现一个严重的问题,ascii码只是对英文的字符进行编码,可是这个世界上的语言文字又不仅仅只有英文,我们常用的汉字就有几千个,可ascii码只能对128个字符进行编码,这让我们中国人咋办

于是乎,我们中国人就搞出了GB2312,GBK这两个字符集,ascii用一个字节进行编码,我们汉字太多,因此我们用多个字节进行编码。

中国人搞一套,法国人搞一套,俄罗斯人又搞了一套,渐渐的,就乱套了。

干脆,搞一个大点的字符集,把这个世界上所有的字符都进行编码,然后大家就用这套编码来处理文本,这就是unicode字符集。

2.2 大一统的问题


unicode只是一个字符集,它规定了不同的字符在二进制上的表示形式,比如“升”这个汉字,它的unicode编码是 \u5347,5347是16进制,转换成成10进制是21319,转成二进制是101 0011 0100 0111,这一个汉字,至少需要2个字节来表示。

下面的代码,演示了获取一个汉字的编码内容

# 1 转成unicode
ch = '升'
ch_unicode = ch.encode('unicode_escape')
print(ch_unicode)

# 2 转成16进制形式
ch_hex = "0x" + str(ch_unicode,encoding='utf-8')[2:]
print(ch_hex)

# 3 转成10进制
ch_int = eval(ch_hex)
print(ch_int)

# 4 转成二进制
print(bin(ch_int))


程序运行结果

b'\\u5347'
0x5347
21319
0b101001101000111


unicode并没有规定这些字符所对应的二进制代码,但是并没有规定这些二进制代码该如何存储。这个汉字两个字节就能存储,但有些字符需要三个字节,像a这种字符,以前大家用ascii码的时候,用一个字节就能表示,在unicode里如果用两个或者更多字节表示,那么不是很浪费么,而且也与之前的ascii不兼容。

3 utf-8


utf-8解决了unicode的编码问题,它是一种变长的编码方式,ascii码表里的字符仍然用一个字节来存储,一个汉字用三个字节来存储

ascii_a = 'a'
ascii_a_utf8 = ascii_a.encode(encoding='utf-8')
print(ascii_a_utf8, len(ascii_a_utf8))

ch = '升'
ch_utf8 = ch.encode(encoding='utf-8')
print(ch_utf8, len(ch_utf8))



程序运行结果

b'a' 1
b'\xe5\x8d\x87' 3

4 python3里的unicode

在python3中,字符串是以unicode编码的,当你想把一个字符串写入到磁盘上时,就必须指定用哪种编码方式进行存储,否则,就容易出错,比如下面的这段代码

with open('city', 'w') as f:
    f.write('北京')


报的错误是

UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)


有了前面的内容做铺垫,你大概可以知道究竟发生了什么错误。

字符串采用的是unicode字符集,但是文件保存的时候,默认采用ascii编码,这就有问题了,ascii可以表示的范围太有限了,只有128个字符,可是汉字的unicode编码里很容就出现大于128的字节,这就是错误发生的原因,解决这个问题,可以采取下面两种方法

4.1 指定utf-8编码

with open('city', 'w', encoding='utf-8') as f:
    f.write('北京')


4.2 以二进制的形式写入文件

with open('city', 'wb') as f:
    f.write('北京'.encode('utf-8'))


这种方法虽然也行,但并不常用,因为这需要每次写入都对字符串进行utf-8编码,不如第一种方法简单高效

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值