python中文乱码不着急,先看懂字节和字符

Python2.x使用过程中,中文乱码解决最耳熟能详的方法就是在代码前加上#-*- coding:utf-8 –*-

那么为什么需要这么做呢?什么又是字节和字符?下面我们了解下。

我来讲一下字符问题我的理解吧,虽然我对Python的编码处理的具体细节还不太清楚,不过临时稍微看了一下,和Perl的原理也差不多

最重要的是必须区分“字符”和“字节”的不同,“字符”是抽象的,而“字节”是具体的

比如一个“中”字,在不同编码中用如下字节表示:

GBK      Big5        UTF-8     UTF-16LE 
\xD6\xD0  \xA4\xA4  \xE4\xB8\xAD  \x2D\x4E

所谓“抽象”的“字符”的“中”,并不是指“\xD6\xD0”或“\xA4\xA4”或任何字节,应该把它理解成:GBK编码中“\xD6\xD0”字节所指代的那个字符(语言学中的能指→所指),或者UTF-8编码中“\xE4\xB8\xAD”所指代的那个字符,但并不是这些具体字节本身

问题是,抽象的字符要作为数据进行存储和传递,就必须有具体的形式,也就是说你在程序内部实现中,要存储“中”这个字符,你必须采用某些特定的字节。你可以用“\xD6\xD0”,也可以用“\xE4\xB8\xAD”,也可以用“\x2D\x4E”,Python在Windows下采用的是UTF-16LE(?),也就意味着它的“字符”的载体编码是UTF-16LE

sys.setdefaultencoding(name)
Set the current default string encoding used by the Unicode implementation. 

文档上是这么写的,如果我的理解没错的话,这个函数的作用就是改变“字符”的载体编码,sys.setdefaultencoding('gbk')以后,“中”这个字符在程序内部就不是用“\x2D\x4E”来承载,而是用“\xD6\xD0”来承载了

Python2.x里的str和unicode有什么区别呢?从字面意义上看容易混淆,实际上,你可以把它理解成str是“字节串”,unicode是“字符串”(string总是翻译成“字符串”,在这里就很容易把人绕晕),看下面的例子:

# -*- coding: gb2312 -*- 

s = "张三李四"
print len(s) #=> 8
u = s.decode('gbk')
print len(u) #=> 4 

我的脚本编码用的是GBK,而不是UTF-8,你会看到len(s)是8,这是这四个汉字所用的实际8个“字节”,而len(u)是4,这就表示这里有4个“字符”

encode和decode是什么意思呢?所谓编码,就是把意义转换成符号;而解码,就是把符号还原成意义。在这里,encode应该理解成把抽象的字符转换成具体的字节,而decode是把具体的字节还原成抽象的字符

现在的问题是:str类和unicode类都同时具有encode和decode方法,这是一个让我很不以为然的设定。如果按照字节与字符的区分,encode方法是应该只归unicode类所有,decode方法是只归str类所有的,因为“意义”只能转换成“符号”,“意义”再还原成“意义”这本身就没有意义。

假如我们这样:

# -*- coding: gb2312 -*- 

s = "张三李四"
u = s.decode('gbk') # 没问题,字节解码为字符,符号还原为意义
s2 = s.encode('gbk')
 # 出错了!字节没法再编码成字节,除非s全部是ASCII字符,但是这样s2和s是完全等同的,这个操作有什么意义?
u2 = u.decode('gbk')
 # 又出错了!也只能u只包含ASCII字符,u2和u也是完全等同,这个操作也没有意义 

在这里提一下Perl的处理方式,我不知道Python处理编码的原理是否是直接得自Python,还是说这是各门语言共同的做法(但是Ruby又不是这样做的),总之Python2.x是有缺陷的

Perl里只有一种string,它实际也区分字符串和字节串(以UTF-8作为底层的承载编码),但不像Python2.x分str和unicode,而是string内部有一个utf8的flag,这个flag是on的时候,这个string就是一个“字符”串,这个flag是off的时候就是一个“字节”串,它的编码、解码函数如下:

$octets = encode(ENCODING, $string [, CHECK])
$string = decode(ENCODING, $octets [, CHECK])

$octets就是字节串,$string就是字符串,也就是说,encode只对$string起作用,而decode只对$octets起作用,不像Python是str和unicode两类两个方法都有,但是其实各有一个是没用的。LarryWall是语言学家,他设计的这一套字符、字节关系是完全符合语言学中的“能指-所指”理论的,而GvR恐怕就对语言学不在行了,Python的处理就不怎么精妙了。

再来说一下file.write为什么有编码问题:

# -*- coding: gb2312 -*-
s = "张三李四"
u = s.decode('gbk') 

f = open('text.txt','w')
f.write(u) # 出错!
f.write(u.encode('gbk')) # 这样才行 

出错的原因很简单,你想输出的是“字符”,而不是“字节”。上面说过,“字符”是抽象的,你是没有办法把一个抽象的东西写到文件里去的。虽然抽象的字符下面肯定是有具体的承载字节的,但是Python似乎并不愿意把unicode底层的字节跟IO搅在一起,这就导致f.write(a_unicode)的失败,当然a_unicode假如只包含ASCII字符,这个可以成功,然而这是一种捷径,是一条让人越来越糊涂的捷径

然后再是u标记的意义是什么?很简单,就是自动完成字节→字符的转换

# -*- coding: gb2312 -*- 

s_or_u1 = "张三李四"
print type(s_or_u1) #=> <type 'str'> 

s_or_u2 = u"张三李四"
print type(s_or_u2) #=> <type 'unicode'> 

u"张三李四"就相当于"张三李四".decode(a_enc),这里的a_enc就是#coding行设定的gb2312

不得不说,(不知是不是从Perl得来的)这套字符处理方式很晦涩,字符、字节区分的概念实在不太容易理解,而Python本身的细节处理也没有做好,Perl做得很干净了,都不容易理解,Python没做干净更不行了。另外再附赠简单介绍Ruby的字符处理方式,跟Perl完全不同:

Ruby中没有字符、字节的区分,一切字符串都是“带有一个编码属性的字节串”。因为没有抽象的字符,所以就没有字节→字符的转换,也就根本没有、也不需要decode方法,Ruby的String类只有encode方法。因为没有抽象的“字符”概念,Ruby的编码问题应该比Perl、Python容易理解。没有“字符”的还有一个好处是:处理多字节文本无需经过中间转换。你要在Perl里处理中文字符,来源文件是GBK编码的,实际都得先转换成UTF-8,Perl才能处理:Python要先转化成UTF-16才能处理。对于海量文本来说,这一转换过程肯定是要耗费一定的资源的。而Ruby不需要这种转换,直接就能处理GBK或其他编码了。可能这样做也是考虑了日文的实际,日文的shift-jis(?)是本土编码,根本都不跟ASCII兼容,不像GBK是跟ASCII兼容的,这样做就不必转换就能处理土著编码的文档了。如果说Perl的字符-字节区分是语言学家的学院派做法的话,Ruby就是契合了多字节字符处理需要的实用派做法。

总结

以上就是本文关于python中文乱码不着急,先看懂字节和字符的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!

(0)

相关推荐

  • Python每天必学之bytes字节

    Python中的字节码用b'xxx'的形式表示.x可以用字符表示,也可以用ASCII编码形式\xnn表示,nn从00-ff(十六进制)共256种字符. 一.基本操作 下面列举一下字节的基本操作,可以看出来它和字符串还是非常相近的: In[40]: b = b"abcd\x64" In[41]: b Out[41]: b'abcdd' In[42]: type(b) Out[42]: bytes In[43]: len(b) Out[43]: 5 In[44]: b[4] Out[44]

  • 深入Python解释器理解Python中的字节码

    我最近在参与Python字节码相关的工作,想与大家分享一些这方面的经验.更准确的说,我正在参与2.6到2.7版本的CPython解释器字节码的工作. Python是一门动态语言,在命令行工具下运行时,本质上执行了下面的步骤: 当第一次执行到一段代码时,这段代码会被编译(如,作为一个模块加载,或者直接执行).根据操作系统的不同,这一步生成后缀名是pyc或者pyo的二进制文件. 解释器读取二进制文件,并依次执行指令(opcodes). Python解释器是基于栈的.要理解数据流向,我们需要知道每条指

  • Python使用dis模块把Python反编译为字节码的用法详解

    dis - Disassembler for Python bytecode,即把python代码反汇编为字节码指令. 使用超级简单: python -m dis xxx.py Python 代码是先被编译为字节码后,再由Python虚拟机来执行字节码, Python的字节码是一种类似汇编指令的中间语言, 一个Python语句会对应若干字节码指令,虚拟机一条一条执行字节码指令, 从而完成程序执行. Python dis 模块支持对Python代码进行反汇编, 生成字节码指令. 当我在网上看到wh

  • Python中struct模块对字节流/二进制流的操作教程

    前言 最近使用Python解析IDX文件格式的MNIST数据集,需要对二进制文件进行读取操作,其中我使用的是struct模块.查了网上挺多教程都写的挺好的,不过对新手不是很友好,所以我重新整理了一些笔记以供快速上手. 注:教程中以下四个名词同义:二进制流.二进制数组.字节流.字节数组 快速上手 在struct模块中,将一个整型数字.浮点型数字或字符流(字符数组)转换为字节流(字节数组)时,需要使用格式化字符串fmt告诉struct模块被转换的对象是什么类型,比如整型数字是'i',浮点型数字是'f

  • python字符串str和字节数组相互转化方法

    实例如下: # bytes object b = b"example" # str object s = "example" # str to bytes bytes(s, encoding = "utf8") # bytes to str str(b, encoding = "utf-8") # an alternative method # str to bytes str.encode(s) # bytes to str

  • 基于python的字节编译详解

    定义: 把模块定义成二进制语言程序的这个过程叫做字节编译 python是解释型语言,它的字节编译是由解释器完成的 编译py文件,生成pyc结尾的文件的方法, 方法一: Import zipfile.py 方法二: 以上这篇基于python的字节编译详解就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们.

  • python中文乱码不着急,先看懂字节和字符

    Python2.x使用过程中,中文乱码解决最耳熟能详的方法就是在代码前加上#-*- coding:utf-8 –*- 那么为什么需要这么做呢?什么又是字节和字符?下面我们了解下. 我来讲一下字符问题我的理解吧,虽然我对Python的编码处理的具体细节还不太清楚,不过临时稍微看了一下,和Perl的原理也差不多 最重要的是必须区分"字符"和"字节"的不同,"字符"是抽象的,而"字节"是具体的 比如一个"中"字,

  • 彻底搞懂 python 中文乱码问题(深入分析)

    前言 曾几何时 Python 中文乱码的问题困扰了我很多很多年,每次出现中文乱码都要去网上搜索答案,虽然解决了当时遇到的问题但下次出现乱码的时候又会懵逼,究其原因还是知其然不知其所以然.现在有的小伙伴为了躲避中文乱码的问题甚至代码中不使用中文,注释和提示都用英文,我曾经也这样干过,但这并不是解决问题,而是逃避问题,今天我们一起彻底解决 Python 中文乱码的问题. 基础知识ASCII 很久很久以前,有一群人,他们决定用8个可以开合的晶体管来组合成不同的状态,以表示世界上的万物.他们看到8个开关

  • 解决c++调用python中文乱码问题

    windows中文操作系统下,vs的c++项目默认编码是GB2312 python默认是utf-8编码 最好在c++程序顶上加: #pragma execution_character_set("GB2312") c++中的字符串一定就是gbk编码 传入python前要做编码转换 准备一个gbk转utf8的函数,如下(网上的): string GbkToUtf8(const char* src_str) { int len = MultiByteToWideChar(CP_ACP, 0

  • 解决python中文乱码问题方法总结

    在运行这样类似的代码: #!/usr/bin/env pythons="中文"print s 最近经常遇到这样的问题: 问题一: SyntaxError: Non-ASCII character '\xe4' in file E:\coding\python\Untitled 6.py on line 3, but no encoding declared; see http://www.python.org/peps/pep-0263.html for details 问题二: Un

  • python 中文乱码问题深入分析

    在本文中,以'哈'来解释作示例解释所有的问题,"哈"的各种编码如下: 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

  • linux下python中文乱码解决方案详解

    1. 场景描述 linux服务器下安装了Anaconda3,执行Pyhton的K-means算法,结果出现如下图的中文字符乱码.上次已经解决了,忘记记录解决流程了,这次配置了一台新的服务器,又出现,默认不配置的话matplotlib画图就会乱码,这次把解决过程记录下,希望能帮助自己和有需要的朋友. 2. 解决方案 网上有好几个解决方案,只介绍自己实战可行的. 1. 查看matplotlib字体位置 python import matplotlib print(matplotlib.matplot

  • python中文乱码的解决方法

    乱码原因:源码文件的编码格式为utf-8,但是window的本地默认编码是gbk,所以在控制台直接打印utf-8的字符串当然是乱码了! 解决方法:1.print mystr.decode('utf-8').encode('gbk')2.比较通用的方法: 复制代码 代码如下: import systype = sys.getfilesystemencoding()print mystr.decode('utf-8').encode(type)

  • 布同 Python中文问题解决方法(总结了多位前人经验,初学者必看)

    因为Python是自带文档,可以通过help函数来查询每一个系统函数的用法解释说明.一般来说,关键的使用方法和注意点在这个系统的文档中都说的很清楚.我试图在网上找过系统文档的中文版的函数功能解释,但是都没有找到,所以我决定将就使用英文版的系统自带的函数解释来学习. 如果你想进行Tkinter和wxPython编程,想要知道一般的widget的使用方法和属性介绍,英文又不是太好的话,我推荐你,你可以去看看<Python与Tkinter编程>这本书,里面392页到538页的附录B和附录C选择了常用

  • 解决Python网页爬虫之中文乱码问题

    Python是个好工具,但是也有其固有的一些缺点.最近在学习网页爬虫时就遇到了这样一种问题,中文网站爬取下来的内容往往中文显示乱码.看过我之前博客的同学可能知道,之前爬取的一个学校网页就出现了这个问题,但是当时并没有解决,这着实成了我一个心病.这不,刚刚一解决就将这个方法公布与众,大家一同分享. 首先,我说一下Python中文乱码的原因,Python中文乱码是由于Python在解析网页时默认用Unicode去解析,而大多数网站是utf-8格式的,并且解析出来之后,python竟然再以Unicod

  • 解决Python2.7读写文件中的中文乱码问题

    Python2.7对于中文编码的问题处理的并不好,这几天在爬数据的时候经常会遇到中文的编码问题.但是本人对编码原理不了解,也没时间深究其中的原理.在此仅从应用的角度做一下总结, 1.设置默认编码 在Python代码中的任何地方出现中文,编译时都会报错,这时可以在代码的首行添加相应说明,明确utf-8编码格式,可以解决一般情况下的中文报错.当然,编程中遇到具体问题还需具体分析啦. #encoding:utf-8 或者 # -*- coding: utf-8 -*- import sys reloa

随机推荐