【Python】中文乱码问题与解决方案 深入分析

2023-05-16

一直以来,python中的中文编码就是一个极为头大的问题,经常抛出编码转换的异常,python中的str和unicode到底是一个什么东西呢?

在本文中,以'哈'来解释作示例解释所有的问题,“哈”的各种编码如下:
1. UNICODE (UTF8-16),C854;
2. UTF-8,E59388;
3. GBK,B9FE。


一、python中的str和unicode

一直以来,python中的中文编码就是一个极为头大的问题,经常抛出编码转换的异常,python中的str和unicode到底是一个什么东西呢?
在python中提到unicode,一般指的是unicode对象,例如'哈哈'的unicode对象为

u'\u54c8\u54c8'

而str,是一个字节数组,这个字节数组表示的是对unicode对象编码(可以是utf-8、gbk、cp936、GB2312)后的存储的格式。这里它仅仅是一个字节流,没有其它的含义,如果你想使这个字节流显示的内容有意义,就必须用正确的编码格式,解码显示。
例如:
 

对于unicode对象哈哈进行编码,编码成一个utf-8编码的str-s_utf8,s_utf8就是是一个字节数组,存放的就是'\xe5\x93\x88\xe5\x93\x88',但是这仅仅是一个字节数组,如果你想将它通过print语句输出成哈哈,那你就失望了,为什么呢?

因为print语句它的实现是将要输出的内容传送了操作系统,操作系统会根据系统的编码对输入的字节流进行编码,这就解释了为什么utf-8格式的字符串“哈哈”,输出的是“鍝堝搱”,因为 '\xe5\x93\x88\xe5\x93\x88'用GB2312去解释,其显示的出来就是“鍝堝搱”。这里再强调一下,str记录的是字节数组,只是某种编码的存储格式,至于输出到文件或是打印出来是什么格式,完全取决于其解码的编码将它解码成什么样子。

这里再对print进行一点补充说明:当将一个unicode对象传给print时,在内部会将该unicode对象进行一次转换,转换成本地的默认编码(这仅是个人猜测)

二、str和unicode对象的转换

str和unicode对象的转换,通过encode和decode实现,具体使用如下:

将GBK'哈哈'转换成unicode,然后再转换成UTF8

三、Setdefaultencoding

如上图的演示代码所示:

当把s(gbk字符串)直接编码成utf-8的时候,将抛出异常,但是通过调用如下代码:

import sys

reload(sys)
sys.setdefaultencoding('gbk')

后就可以转换成功,为什么呢?在python中str和unicode在编码和解码过程中,如果将一个str直接编码成另一种编码,会先把str解码成unicode,采用的编码为默认编码,一般默认编码是anscii,所以在上面示例代码中第一次转换的时候会出错,当设定当前默认编码为'gbk'后,就不会出错了。

至于reload(sys)是因为Python2.5 初始化后会删除 sys.setdefaultencoding 这个方法,我们需要重新载入。

四、操作不同文件的编码格式的文件

建立一个文件test.txt,文件格式用ANSI,内容为:

abc中文

用python来读取:

# coding=gbk

print(open("Test.txt").read())

结果:

abc中文

把文件格式改成UTF-8:

结果:

abc涓枃

显然,这里需要解码:

# coding=gbk

import codecs

print(open("Test.txt").read().decode("utf-8"))

结果:

abc中文

上面的test.txt我是用Editplus来编辑的,但当我用Windows自带的记事本编辑并存成UTF-8格式时,

运行时报错:

Traceback (most recent call last):

File "ChineseTest.py", line 3, in 

print open("Test.txt").read().decode("utf-8")

UnicodeEncodeError: 'gbk' codec can't encode character u'\ufeff' in position 0: illegal multibyte sequence

原来,某些软件,如notepad,在保存一个以UTF-8编码的文件时,会在文件开始的地方插入三个不可见的字符(0xEF 0xBB 0xBF,即BOM)。

因此我们在读取时需要自己去掉这些字符,python中的codecs module定义了这个常量:

# coding=gbk

import codecs
data = open("Test.txt").read()

if data[:3] == codecs.BOM_UTF8:
    data = data[3:]
    print(data.decode("utf-8"))

结果:

abc中文

五、文件的编码格式和编码声明的作用

源文件的编码格式对字符串的声明有什么作用呢?这个问题困扰一直困扰了我好久,现在终于有点眉目了,文件的编码格式决定了在该源文件中声明的字符串的编码格式,例如:

str = '哈哈'
print(repr(str))

a.如果文件格式为utf-8,则str的值为:'\xe5\x93\x88\xe5\x93\x88'(哈哈的utf-8编码)

b.如果文件格式为gbk,则str的值为:'\xb9\xfe\xb9\xfe'(哈哈的gbk编码)

在第一节已经说过,python中的字符串,只是一个字节数组,所以当把a情况的str输出到gbk编码的控制台时,就将显示为乱码:鍝堝搱;而当把b情况下的str输出utf-8编码的控制台时,也将显示乱码的问题,是什么也没有,也许'\xb9\xfe\xb9\xfe'用utf-8解码显示,就是空白吧。>_<

说完文件格式,现在来谈谈编码声明的作用吧,每个文件在最上面的地方,都会用# coding=gbk 类似的语句声明一下编码,但是这个声明到底有什么用呢?到止前为止,我觉得它的作用也就是三个:

  1. 声明源文件中将出现非ascii编码,通常也就是中文;
  2. 在高级的IDE中,IDE会将你的文件格式保存成你指定编码格式。
  3. 决定源码中类似于u'哈'这类声明的将‘哈'解码成unicode所用的编码格式,也是一个比较容易让人迷惑的地方,看示例:
#coding:gbk

ss = u'哈哈'
print(repr(ss))
print('ss:%s' % ss)

将这个些代码保存成一个utf-8文本,运行,你认为会输出什么呢?大家第一感觉肯定输出的肯定是:

u'\u54c8\u54c8'

ss:哈哈

但是实际上输出是:

u'\u935d\u581d\u6431'

ss:鍝堝搱

为什么会这样,这时候,就是编码声明在作怪了,在运行ss = u'哈哈'的时候,整个过程可以分为以下几步:

1) 获取'哈哈'的编码:由文件编码格式确定,为'\xe5\x93\x88\xe5\x93\x88'(哈哈的utf-8编码形式)

2) 转成 unicode编码的时候,在这个转换的过程中,对于'\xe5\x93\x88\xe5\x93\x88'的解码,不是用utf-8解码,而是用声明编码处指定的编码GBK,将'\xe5\x93\x88\xe5\x93\x88'按GBK解码,得到就是''鍝堝搱'',这三个字的unicode编码就是u'\u935d\u581d\u6431',至止可以解释为什么print repr(ss)输出的是u'\u935d\u581d\u6431' 了。

好了,这里有点绕,我们来分析下一个示例:

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

ss = u'哈哈'
print(repr(ss))
print('ss:%s' % ss)

将这个示例这次保存成GBK编码形式,运行结果,竟然是:

UnicodeDecodeError: 'utf8' codec can't decode byte 0xb9 in position 0: unexpected code byte

这里为什么会有utf8解码错误呢?想想上个示例也明白了,转换第一步,因为文件编码是GBK,得到的是'哈哈'编码是GBK的编码'\xb9\xfe\xb9\xfe',当进行第二步,转换成 unicode的时候,会用UTF8对'\xb9\xfe\xb9\xfe'进行解码,而大家查utf-8的编码表会发现,utf8编码表(关于UTF- 8解释可参见字符编码笔记:ASCII、UTF-8、UNICODE)中根本不存在,所以会报上述错误。

>>> 希望对你有帮助,如果你还有其他问题,可在评论区讨论~

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【Python】中文乱码问题与解决方案 深入分析 的相关文章

随机推荐

  • DataTables从安装到入门的详细教程之一:DataTables介绍及安装

    DataTables介绍 Datatables是一款jquery表格插件 它是一个高度灵活的工具 xff0c 可以将任何HTML表格添加高级的交互功能 分页 xff0c 即时搜索和排序 几乎支持任何数据源 xff1a DOM xff0c j
  • CSS换行和不换行

    强制不换行 div white space nowrap 自动换行 div word wrap break word word break normal 强制英文单词断行 div word break break all
  • Linux:Shell脚本基本命令

    24 span class token keyword if span span class token punctuation span span class token punctuation span span class token
  • Spring Boot设置值:分别用@ConfigurationProperties和@Value给属性设值及其区别

    目录 64 ConfigurationProperties给属性映射值 编写JavaBean 编写配置文件 测试类 xff1a 运行结果 xff1a 64 Value给属性设置值 编写JavaBean 运行结果 xff1a 64 Confi
  • Mac Intrellij IDEA中使用debug调试

    目录 一 Debug开篇 二 基本用法 amp 快捷键 三 变量查看 四 计算表达式 五 智能步入 六 断点条件设置 七 多线程调试 八 回退断点 九 中断Debug 十 附 xff1a JRebel激活 Debug用来追踪代码的运行流程
  • Docker创建容器步骤解析

    创建hello world容器 以创建一个简单的hello world容器为例 xff0c 介绍docker创建容器的几大步骤 运行命令 xff1a docker run hello world docker运行步骤分析
  • 什么是代理服务器及其作用

    什么是代理服务器 代理服务器 xff08 Proxy Server xff09 是网上提供转接功能的服务器 xff0c 在一般情况下 xff0c 我们使用网络浏览器直接去连接其他Internet站点取得网络信息时 xff0c 是直接联系到目
  • sudo apt-get update执行失败问题解决

    错误 在执行sudo apt get update命令时 xff0c 执行结果失败 xff0c 错误信息如下 xff1a 获取 xff1a 1 http repo mysql com trusty InRelease 33 5 kB 100
  • @EntityListeners(AuditingEntityListener.class)介绍

    64 EntityListeners 源码 Specifies the callback listener classes to be used for an entity or mapped superclass This annotat
  • windows配置hadoop(详细)

    一 环境 windows7 64位 hadoop2 7 二 安装java1 8 xff0c 并配置环境变量 下载地址 xff1a http www oracle com technetwork java javase downloads j
  • Windows更新策略配置

    两个步骤 1 开启自动更新服务 2 配置自动更新策略 开启服务 Windows Update的服务名为wuauserv 可以通过命令行的方式进行开启 xff08 管理员权限 xff09 xff0c sc命令使用方法 xff1a sc命令使用
  • 数据库、MySQL与Python这一篇就够了

    lt 1 gt 数据库介绍 什么是数据库 xff1f 数据库 xff08 Database xff09 是按照数据结构来组织 存储和管理数据的仓库 xff0c 每个数据库都有一个或多个不同的API用于创建 xff0c 访问 xff0c 管理
  • Python:同行if...else...详细教程

    我最近为游戏Apple Clicker写成就系统 xff0c 加上后整个程序的代码竟然超过2200行 xff0c 窗口启动时间也很慢 xff0c 主要是if else 使用的太多 于是查了查缩短代码的方法 xff0c 总结如下 xff1a
  • ARM:驱动开发1

    linux内核模块 1 模块三要素 xff1a 内核模块不能单独执行 xff0c 也不能自动执行 span class token comment 入口 xff1a span span class token keyword static
  • Python:环境变量配置方法 详细教程

    最近有人问我如何配置python环境变量 xff0c 这篇文章就向大家介绍python环境变量配置方法 python环境变量的配置方法 xff1a 首先鼠标右键此电脑 xff0c 选择属性 xff1b 然后点击高级系统设置 xff0c 点击
  • Python - 字符串格式化详解(%、format)

    有人问我python的format函数怎么用 xff0c 这篇文章向大家介绍format函数用法 Python在字符串格式化的两种方式 format xff0c 关于整数的输出 o xff1a oct 八进制 d xff1a dec 十进制
  • Python 字典(Dictionary)操作详解

    这篇文章主要介绍了Python 字典 Dictionary 的详细操作方法 xff0c 需要的朋友可以参考下 Python字典是另一种可变容器模型 xff0c 且可存储任意类型对象 xff0c 如字符串 数字 元组等其他容器模型 一 创建字
  • Python中zipfile压缩包模块的使用

    本文主要介绍了Python中zipfile压缩包模块的使用 xff0c zipfile 模块提供了创建 读取 写入 添加及列出 ZIP 文件的工具 xff0c 本文做一个简单的总结 简介 ZIP 文件格式是一个常用的归档与压缩标准 xff0
  • python中@contextmanager实例用法总结

    本文是对python中 64 contextmanager的简单总结 在对于python中的装饰器 xff0c 我们一般会使用它辅助方法 在我们学习的上下文管理器中 xff0c 有一个 64 contextmanager装饰器 xff0c
  • 【Python】中文乱码问题与解决方案 深入分析

    一直以来 xff0c python中的中文编码就是一个极为头大的问题 xff0c 经常抛出编码转换的异常 xff0c python中的str和unicode到底是一个什么东西呢 xff1f 在本文中 xff0c 以 39 哈 39 来解释作