您的位置:首页 > 编程语言 > Python开发

解决python的中文字符编码问题

2018-07-15 17:00 113 查看
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_28739605/article/details/81054631

博客搬家,新博客地址
https://imlogm.github.io/%E8%87%AA%E7%84%B6%E8%AF%AD%E8%A8%80%E5%A4%84%E7%90%86/character-encoding/

摘要:最近在做自然语言处理相关的项目,发现中文编码的问题实在需要好好学习下,我用python为例,简单介绍下python编程时如何处理好中文编码的问题。

关键字:自然语言处理, 字符编码, python

1. 从字符编码谈起

讲真,字符编码是很大的一块内容,单用一篇博客是完全讲不完的。这里借用一下大佬的文章:字符编码笔记:ASCII,Unicode 和 UTF-8 - 阮一峰的日志

看完上面的那篇文章之后,相信你对字符编码有了一定的认识。在中文的自然语言处理中,最常遇到的是ASCII,Unicode,UTF-8,GB2312,GBK等。这几种编码,你都可以搜索相关的文章看下,我这里就不展开介绍了。直接用几个python的程序解释下如何在python中处理字符编码的问题。

2. 关于python的str类型和print过程

比如一段程序:

# -*- coding:utf-8 -*-

s = "这是一段中文"  # s是str类型的变量
print(s)

# 程序输出:“这是一段中文”

这段程序中的变量s就是str类型的。我们都知道计算机内部都是二进制的0和1,str类型就是这样的0和1组成的二进制字节流,也就是说这里的变量s在计算机内部是一段二进制字节,并不是字符串。

如果你是在python的交互式编程环境中,那么你可以做个实验:

>>> s = "这是一段中文"
>>> s
\xe8\xbf\x99\xe6\x98\xaf\xe4\xb8\x80\xe6\xae\xb5\xe4\xb8\xad\xe6\x96\x87

\x
表示这个数是十六进制数,
\xe8
表示这个数是十六进制数“E8”,转换为二进制为
11101000
,上面的“\xe8\xbf\x99\xe6\x98\xaf\xe4\xb8\x80\xe6\xae\xb5\xe4\xb8\xad\xe6\x96\x87”就是变量s所代表的字节流,换句话说,就是字符串“这是一段中文”在utf-8编码格式下的二进制表示。

这里就出现了两个问题:

  1. 变量s赋值时,一段中文字符串是怎么变成二进制字节流的?
  2. 打印变量s时,二进制字节流是怎么变成一段中文字符串的?

首先是问题1。变量s赋值时,字符串经过某种编码方式编码(encode)成为二进制字节,再赋值给变量s。这里的“某种编码方式”由代码显式指出,代码的第一行

# -*- coding:utf-8 -*-
就是用来显式地告诉计算机,你在str类型赋值时,用utf-8的编码方式。

然后是问题2。打印变量s时,二进制字节流通过某种编码方式解码(decode)为字符串。这里的“某种编码方式”由操作系统指出。我用的ubuntu系统使用的是utf-8的编码方式。

注意体会

编码
解码
这两个词的不同。编码方式和解码方式一样,才能正常print,否则显示的是乱码。

可能你还是不太明白,我们用上面的程序再做一组实验。因为每台电脑的命令行的编码方式不一样,我用的是ubuntu的系统,编码格式是utf-8,我以我的电脑为例来讲解。同时,注意实验要在命令行的状态下进行。有些ide比较智能,会自动更换输出环境的编码格式,达不到实验效果。

第一个程序和上面的一样,我们来看下效果:

# -*- coding:utf-8 -*-

# 命令行的编码方式为utf-8

s = "这是一段中文"  # s是str类型的变量,计算机把字符串以utf-8格式编码成二进制字节,赋值给s

print(s)    # s是str类型的变量,计算机读取s(也就是读取出二进制字节),然后以utf-8格式解码为字符串

# 程序输出:“这是一段中文”

然后,我们改动第一行:

# -*- coding:GBK -*-

# 命令行的编码方式为utf-8

s = "这是一段中文"  # s是str类型的变量,计算机把字符串以GBK格式编码成二进制字节,赋值给s

print(s)    # s是str类型的变量,计算机读取s(也就是读取出二进制字节),然后以utf-8格式解码为字符串

# 程序输出:一段乱码

我们再做第三个实验:

# -*- coding:utf-8 -*-

# 命令行的编码方式为GBK

s = "这是一段中文"  # s是str类型的变量,计算机把字符串以utf-8格式编码成二进制字节,赋值给s

print(s)    # s是str类型的变量,计算机读取s(也就是读取出二进制字节),然后以GBK格式解码为字符串

# 程序输出:一段乱码

我想你应该能理解这三个程序之间的区别。

2. 关于unicode类型

unicode类型是python中的一种字符串类型,在计算机内也是二进制字节。不过不同于str是单纯的二进制字节,unicode类型特指由ucs2或者ucs4编码格式编码的二进制字节。

如果你在python的交互式编程环境中,你可以做个实验:

>>> s = u"这是一段中文"    # 这边多了个u,表示变量s为unicode变量
>>> s
u'\u8fd9\u662f\u4e00\u6bb5\u4e2d\u6587'

可以看到,和上面str类型的实验结果的

\x
不一样了,这里出现的是
\u
\u
代表了在unicode编码表中的位置,比如
\u8fd9
就代表unicode编码表中8fd9这个位置的字符。

python中unicode类型的变量是作为一个中转站存在的。比如你要把一段字符串从utf-8编码转为GBK编码,你需要做的是:

# -*- coding:utf-8 -*-

s = "这是一段中文"  # s是str类型的变量,计算机把字符串以utf-8格式编码成二进制字节,赋值给s

s.decode("utf-8")   # 二进制字节s以utf-8格式解码到unicode,解码后s从str类型变为unicode类型

s.encode("GBK")     # unicode类型的变量s被以GBK格式编码为二进制字符串,编码后变量s从unicode类型变为str类型

# 程序输出:一段乱码

反过来,要把一个GBK编码的字符串转为utf-8也一样,要以unicode作为中转站。

3. sys.setdefaultencoding(‘utf-8’)

网上一些教程会教你,在遇到中文编码问题的时候,在代码的开头加上这几句:

# -*- coding:utf-8 -*-
import sys
reload(sys)
sys.setdefaultencoding('utf-8')

你一试,还真的解决了问题,但你不知道这几句话有什么用。

第一句

# -*- coding:utf-8 -*-
上一段已经说了,是为了显式地说明代码是由utf-8格式编码的,如果你不加的话,一般来说是采用默认编码ascii。ascii不支持中文,你的代码中有任何中文就会出错。

后面三句,最重要的是

sys.setdefaultencoding('utf-8')
,它的目的是修改默认的解码方式为utf-8。

看下面的实验:

# -*- coding: utf-8 -*-
s = '中文字符'  # s是字符串经过utf-8编码格式编码后的二进制字节,str类型
s.encode('GBK') # s是二进制字节,它不会直接encode。python会首先调用decode,将s从str类型变为unicode格式,再用GBK编码为str类型

你可以使用以下代码获取python默认的解码方式:

import sys
print(sys.getdefaultencoding())

假如你获取到的默认解码方式为ascii。那么:

# -*- coding: utf-8 -*-
s = "这是一段中文"  # s是字符串经过utf-8编码格式编码后的二进制字节,str类型
s.encode("GBK") # s是二进制字节,它不会直接encode。python会首先调用decode,将s从str类型变为unicode格式,再用GBK编码为str类型

# 如果你的默认解码方式为ascii,那么上面一句话在实际执行时,相当于下面这句话
s.decode("ascii").encode("GBK")

显然,程序会报错:UnicodeDecodeError: ‘ascii’ codec can’t decode byte 0xe4 in position 。

解决方法1,显示地指明解码格式:

# -*- coding: utf-8 -*-
s = "这是一段中文"

s.decode("utf-8").encode("GBK")

解决方法2,修改默认解码方式:

# -*- coding: utf-8 -*-
import sys
reload(sys)
sys.setdefaultencoding('utf-8')

s = "这是一段中文"

s.encode("GBK")

你应该能从这几个实验中明白

sys.setdefaultencoding('utf-8')
的作用。

4. 检验学习成果

python常见编码错误集合 - 妙音的博客

看看上面链接的博客里所列举的几个错误示例,现在你是否能够一眼就找出错误点,并给出解决方法呢?

阅读更多
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: