一:什么是编码

  将明文转换为计算机可以识别的编码文本称为“编码”。反之从计算机可识别的编码文本转回为明文为“解码”。

  那么什么是明文呢,首先我们从一段信息说起,消息以人们可以理解,易懂的表示存在,我们把这个表示为明文(plain text)。对于说英文的人,纸张上打印的或者屏幕上显示的英文都算是明文。

二:都有什么编码格式?

1:ASCII(占一个字符,只支持英文)

  计算机上的数据都是以二进制的形式存储的,1个字节(8比特)可以表示256种状态,英文只有26个字符,再加上一些特殊的字符,使用128个就够了,计算机就可以使用127个不同字节来表示英文文字,这就是ASCII码

2:GB2312(占两个字符,支持6700+汉字)

  计算机进入中国后,无法显示中文,一个字节已经被占满了,我国重新制定了一个编码表,将扩展的第八位对应的拉丁文全部删掉,规定一个小于127的字符与原来的意义相同,当两个大于127的字符连接在一起的时候,就表示一个汉字,前面一个字节为高字节,后面一个字节为低字节,这样就可以表示7000多汉字,这种编码叫做GB2312。GB2312是对ASCII的中文扩展

3:GBK和GB18030(GB2312的升级版,支持21000+汉字)

  由于汉字的数量太大,GB2312是不能满足需求,后面规定只要第一个字节大于127就固定表示一个汉字,不管后面的是不是扩展字符里面的内容,扩展后的编码称为GBK,GBK包括了GB2312的所有内容,同时增加了近20000个新的汉字和符号

4:Shift-JIS 日本编码(这里不过多解释)

5:TIS-620泰国编码(这里不过多解释)

6:ks_c_5601-1987韩国编码(这里不过多解释)

  由于每个国家都有自己的字符,所以其对应关系也涵盖了自己国家的字符,但是以上编码都存在局限性,即:仅涵盖本国字符,无其他国家字符的对应关系。应运而生出现了万国码,他涵盖了全球所有的文字和二进制的对应关系

7:Unicode(2-4字节,已经收录了136690个字符,并一直扩展)

  在uincode出现之前,每隔国家都搞自己的编码,彼此之间互不支持,带来了许多不方便,国际标准组织提出来一个统一的编码标准:unicode

  unicode用两个字符来表示一个字符,可以提供65535种字符,足够覆盖世界上所有的字符

8:UTF-8(Unicode Transformation Format)

  unicode的出现,提供了统一的标准,但对于英文世界来说,一个字节完全够用,如果使用unicode会浪费大量的空间,为了解决这个问题提出来utf-8,一种针对unicode的可变长度字符串,可以使用1-4个字符表示一个符号,根据不同的符号变化字节长度,当字符在ASCII编码范围内,用一个字节表示,兼用ASCII。

  使用这样编码的好处是,虽然内存汇总的数据都是unicode,但是当数据保存到磁盘或者用于网络传输时,使用utf-8会节省更多的流量和硬盘空间。

  • UTF-8: 使用1、2、3、4个字节表示所有字符;优先使用1个字符、无法满足则使增加一个字节,最多4个字节。英文占1个字节、欧洲语系占2个、东亚占3个,其它及特殊字符占4个
  • UTF-16: 使用2、4个字节表示所有字符;优先使用2个字节,否则使用4个字节表示。
  • UTF-32: 使用4个字节表示所有字符;

  unicode和utf-8的关系:unicode是内存编码表示方案,而utf-8是如何保存和传输unicode的方案

三:编码的转换

  虽然国际语言是英语 ,但大家在自己的国家依然说自已的语言,不过出了国, 你就得会英语
编码也一样,虽然有了unicode and utf-8 , 但是由于历史问题,各个国家依然在大量使用自己的编码,比如中国的windows,默认编码依然是gbk,而不是utf-8

  基于此,如果中国的软件出口到美国,在美国人的电脑上就会显示乱码,因为他们没有gbk编码。
  若想让中国的软件可以正常的在 美国人的电脑上显示,只有以下2条路可走:

  1. 让美国人的电脑上都装上gbk编码
  2. 把你的软件编码以utf-8编码

  第1种方法几乎不可能实现,第2种方法比较简单。 但是也只能是针对新开发的软件。 如果你之前开发的软件就是以gbk编码的,上百万行代码可能已经写出去了,重新编码成utf-8格式也会费很大力气。

  so , 针对已经用gbk开发完毕的项目,以上2种方案都不能轻松的让项目在美国人电脑上正常显示,难道没有别的办法了么?
  有, 还记得我们、、讲unicode其中一个功能是其包含了跟全球所有国家编码的映射关系,意思就是,你写的是gbk的“学习”,但是unicode能自动知道它在unicode中的“学习”的编码是什么,如果这样的话,那是不是意味着,无论你以什么编码存储的数据 ,只要你的软件在把数据从硬盘读到内存里,转成unicode来显示,就可以了。
由于所有的系统、编程语言都默认支持unicode,那你的gbk软件放到美国电脑 上,加载到内存里,变成了unicode,中文就可以正常展示啦。

unicode与gbk的映射表 http://www.unicode.org/charts/

  

四:python2.x的编码

  在python2.x中,有两种字符串类型:str类型和unicode类型。这两个类型只是python定义的两个名字,关键还要看这两种数据类型在内存中的存储方法是什么

str和unicode都是basestring的子类。严格意义上说,str其实是字节串,它是unicode经过编码后的字节组成的序列。

  而unicode是一个字符串,str是unicode这个字符串经过编码(utf8,gbk等)后的字节组成的序列。

unicode才是真正意义上的字符串,对字节串str使用正确的字符编码进行解码后获得

在Py2里,str=bytes。python2的字符串其实更应该称为字节串

py2编码的最大特点是Python 2 将会自动的将bytes数据解码成 unicode 字符串

所以在2里我们可以将字节与字符串拼接。

Python 2.7. (v2.7.14:84471935ed, Sep  , ::) [MSC v.  bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> s = '学习'
>>> print type(s)
<type 'str'>
>>> print repr(s)
'\xd1\xa7\xcf\xb0' >>> s = u'学习'
>>> print type(s)
<type 'unicode'>
>>> print repr(s)
u'\u5b66\u4e60'

  由上面的例子可以看出str和unicode分别存储的是字节数据和unicode数据

  但是,python2.x悄悄掩盖掉了byte到unicode的转换,只要数据全部是ASCII的话,所有的转换都是正确的,一个一个非ASCII的字符进入你的程序,那么默认的解码将会失效,从而造成unicodedecodeerror的错误,py2编码让程序在出路ASCII的时候非常简单,付出的代价就是在处理非ASCII的时候将会失败。

由于Python创始人在开发初期认知的局限性,其并未预料到python能发展成一个全球流行的语言,导致其开发初期并没有把支持全球各国语言当做重要的事情来做,所以就轻佻的把ASCII当做了默认编码。 当后来大家对支持汉字、日文、法语等语言的呼声越来越高时,Python于是准备引入unicode,但若直接把默认编码改成unicode的话是不现实的, 因为很多软件就是基于之前的默认编码ASCII开发的,编码一换,那些软件的编码就都乱了。所以Python 2 就直接 搞了一个新的字符类型,就叫unicode类型,比如你想让你的中文在全球所有电脑上正常显示,在内存里就得把字符串存成unicode类型

五:python3.x的编码

  python3.x也有两种数据类型,str和bytes;str类型存unicode数据,bytes类型存bytes数据,

  python3.x将utf-8或者gbk等编码的字节数据转化为python3.x的str类型,utf-8编码的bytes<-->str

  python2.x将utf-8或者gbk等编码的字节数据转化为python2.x的unicode类型,utf-8编码的str<-->unicode

  python3.x的编码思想就是它清晰的将文本和二进制区分开了,不会对bytes字节进行自动编码。文本总是unicode,由str类型表示,二进制数据则由bytes类型表示,Python 3不会以任意隐式的方式混用str和bytes,将两者明确地区分开。基于此,Python3中不能拼接字符串和字节包,也不可以在字节包里搜索字符串(反之亦然),也不能向使用字符串参数的函数中传入字节包参数(反之亦然)。

python3 执行代码的过程

  1. 解释器找到代码文件,把代码字符串按文件头定义的编码加载到内存,转成unicode
  2. 把代码字符串按照语法规则进行解释,
  3. 所有的变量字符都会以unicode编码声明
######在python2.x#######
print(b'hello'+'world')
会输出
helloworld ######在python3.x#######
print(b'hello'+'world')
会输出
TypeError: can't concat str to bytes

  本来这样就可以结束了,但是上面的utf-8编码之所以能在windows gbk的终端下显示正常,是因为到了内存里python解释器把utf-8转成了unicode , 但是这只是python3, 并不是所有的编程语言在内存里默认编码都是unicode,比如 万恶的python2 就不是, 它的默认编码是ASCII,想写中文,就必须声明文件头的coding为gbk or utf-8, 声明之后,python2解释器仅以文件头声明的编码去解释你的代码,加载到内存后,并不会主动帮你转为unicode,也就是说,你的文件编码是utf-8,加载到内存里,你的变量字符串就也是utf-8, 这意味着什么你知道么?。。。意味着,你以utf-8编码的文件,在windows是乱码。

乱是正常的,不乱才不正常,因为只有2种情况 ,你的windows上显示才不会乱

  1. 字符串以GBK格式显示
  2. 字符串是unicode编码

  既然Python2并不会自动的把文件编码转为unicode存在内存里, 那就只能使出最后一招了,你自己人肉转。Py3 自动把文件编码转为unicode必定是调用了什么方法,这个方法就是,decode(解码) 和encode(编码)

  时间来到2008年,python发展已近20年,创始人龟叔越来越觉得python里的好多东西已发展的不像他的初衷那样,开始变得臃肿、不简洁、且有些设计让人摸不到头脑,比如unicode 与str类型,str 与bytes类型的关系,这给很多python程序员造成了困扰。
  龟叔再也忍不了,像之前一样的修修补补已不能让Python变的更好,于是来了个大变革,Python3横空出世,不兼容python2,python3比python2做了非常多的改进,其中一个就是终于把字符串变成了unicode,文件默认编码变成了utf-8,这意味着,只要用python3,无论你的程序是以哪种编码开发的,都可以在全球各国电脑上正常显示,真是太棒啦!

  PY3 除了把字符串的编码改成了unicode, 还把str 和bytes 做了明确区分, str 就是unicode格式的字符, bytes就是单纯二进制啦。

六:文件存储读取过程中的编码问题

  对于文本编辑器word等软件,当我们在这些软件上编辑文字的时候,无论是什么语言的文字或符号,计算机都是无法识别的。
那么在保存之前数据是通过什么形式存在内存的呢?
是unicode数据,为什么要存unicode数据,这是因为无论世界上的任何字符它都有唯一编码对应,兼容性是最好的。
当我们保存了存到磁盘上的数据又是什么呢?
是通过某种编码方式编码的bytes字节串。比如utf8---一种可变长编码,很好的节省了空间;还可以是gbk等编码方式。
在我们的文本编辑器软件都有默认的保存文件的编码方式,比如utf-8,gbk等。当我们保存的时候,这些编辑软件已经"默默地"做了编码工作。
那当我们再打开这个文件时,软件又默默地给我们做了解码的工作,将数据再解码成unicode,然后就可以呈现明文给用户了!
所以,unicode是离用户更近的数据,bytes是离计算机更近的数据。

七:编码与程序运行的关系

编写python代码一般会用到pycharm ,sublime等软件,而代码文件的创建,保存,执行等过程就伴随着编码解码流程,使用pycharm创建的hello.py文件,当我们保存的时候,文件就以pycharm默认的编码方式保存到磁盘,关闭文件再打开,pycharm就会以默认的编码方式对该文件打开后读到的内容就行解码,转成unicode到内存我们就看到了我们的明文;

而如果点开运行按钮或者在命令行运行该文件时候,python解释器就会被调用,打开文件,然后将存储在磁盘上的bytes数据解码成unicode数据,这个过程和编译器是一样的,不同的是解释器将会把这些unicode数据翻译成c代码再转成二进制的数据流,最后通过控制操作系统调用cpu来执行这些二进制数据,整个过程才算结束,

python2.x默认的是ASCII码,python3.x默认的是utf-8,可以通过下面的方式查询:

import sys
print(sys.getdefaultencoding())

八,字符编码转换总结

python2.x

    内存中字符默认编码是ASCII,默认文件编码也是ASCII

    当声明了文件头的编码后,字符串的编码就按照文件编码来,总之,文件编码是什么,那么python2.x的str就是什么

    python2.x的unicode是一个单独的类型,按u"编码"来表示

    python2.x  str==bytes,bytes直接是按照字符编码存成2进制格式在内存里

python3.x

    字符串都是unicode

    文件编码都默认是utf-8,读到内存会被python解释器自动转成unicode

    bytes和str做了明确的区分

    所有的unicode字符编码后都会编程bytes格式

九:print语句和print函数的区别

print语句

在python2.x中,print语句最简单的使用形式是

print hello world!

这相当于执行了

sys.stdout.write(‘’。join(map(str,[hello world!]))+'\n')

如果以逗号为分隔符,传递额外的参数,这些参数会被传递到str()函数,最终打印的时候,每个参数之间会空一行。

从2.0版本开始,python引入了print>>的语法。作用是重定向print语句最终输出的字符串的文件

例如:

print>>output

相当于

output.write(str(hello)+'\n')

print函数

如果用python来实现print的函数,他的函数定义应该是这样的

import sys

def print(*objects, sep=None, end=None, file=None, flush=False):
"""A Python translation of the C code for builtins.print(). """
if sep is None:
sep = ' '
if end is None:
end = '\n'
if file is None:
file = sys.stdout
file.write(sep.join(map(str, objects)) + end)
if flush:
file.flush() 函数定义

  从上面的代码我们可以发现,python3.x的print 函数实现了print语句的所有特性。

一篇文章详解python的字符编码问题的更多相关文章

  1. 详解python的字符编码问题

    一:什么是编码 将明文转换为计算机可以识别的编码文本称为“编码”.反之从计算机可识别的编码文本转回为明文为“解码”. 那么什么是明文呢,首先我们从一段信息说起,消息以人们可以理解,易懂的表示存在,我们 ...

  2. 一篇文章详解iOS之AutoResizing、AutoLayout、sizeClass来龙去脉

    前言 iPhone自诞生以来,随着其屏幕尺寸不断的多样化,屏幕适配的技术一直在发展更新.目前,iOS系统版本已经更新到9.3,XCode的最新版本已经是7.3,仅iPhone历史产品的尺寸就已经有4种 ...

  3. Python常见字符编码间的转换

    主要内容:     1.Unicode 和 UTF-8的爱恨纠葛     2.字符在硬盘上的存储     3.编码的转换     4.验证编码是否转换正确     5.Python bytes类型 前 ...

  4. 详解Python中re.sub--转载

    [背景] Python中的正则表达式方面的功能,很强大. 其中就包括re.sub,实现正则的替换. 功能很强大,所以导致用法稍微有点复杂. 所以当遇到稍微复杂的用法时候,就容易犯错. 所以此处,总结一 ...

  5. 详解Python中内置的NotImplemented类型的用法

    它是什么? ? 1 2 >>> type(NotImplemented) <type 'NotImplementedType'> NotImplemented 是Pyth ...

  6. Python基础-字符编码与转码

    ***了解计算机的底层原理*** Python全栈开发之Python基础-字符编码与转码 需知: 1.在python2默认编码是ASCII, python3里默认是utf-8 2.unicode 分为 ...

  7. 举例详解Python中的split()函数的使用方法

    这篇文章主要介绍了举例详解Python中的split()函数的使用方法,split()函数的使用是Python学习当中的基础知识,通常用于将字符串切片并转换为列表,需要的朋友可以参考下   函数:sp ...

  8. Python的字符编码

    Python的字符编码 1. Python字符编码简介 1. 1  ASCII Python解释器在加载.py文件的代码时,会对内容进行编码,一般默认为ASCII码.ASCII(American St ...

  9. Python常用字符编码(转)

    Python常用字符编码   字符编码的常用种类介绍 第一种:ASCII码 ASCII(American Standard Code for Information Interchange,美国信息交 ...

随机推荐

  1. 安装 redis 拓展

    PHP API 20121113 PHP Extension 20121212 Zend Extension 220121212 Zend Extension Build API220121212,T ...

  2. Wpf窗口中打开WinForm窗口

    获取wpf窗口对应的句柄窗口 using System; using System.Windows; using System.Windows.Interop; using IWin32Window ...

  3. 信号量(Semaphore)

    在python的多线程体系中,一共有4种锁: 同步锁(互斥锁):Lock: 递归锁:RLock: 信号量:Semaphore: 同步条件锁:Condition. 信号量(semaphore)是一种可以 ...

  4. Windows下安装BeautifulSoup4显示'You are trying to run the Python 2 version of Beautiful Soup under Python 3.(`python setup.py install`) or by running 2to3 (`2to3 -w bs4`).'

    按照网上教程,将cmd的目录定位到解压缩文件夹地址,然后 >>python setup.py install ( Window下不能直接解压tar.giz文件,可以使用7z解压软件提取解压 ...

  5. 创建JUtil

    这里拿Dynamic项目来演示,首先创建一个Dynamic项目,起名,点next, 继续点next, 将web.xml文件勾选,finish, 接下来在Java Resources->src下创 ...

  6. 内存栅栏(memory barrier):解救peterson算法的应用陷阱

    最近一个项目中用到了peterson算法来做临界区的保护,简简单单的十几行代码,就能实现两个线程对临界区的无锁访问,确实很精炼.但是在这不是来分析peterson算法的,在实际应用中发现peterso ...

  7. 用不到 50 行的 Python 代码构建最小的区块链

    引用 译者注:随着比特币的不断发展,它的底层技术区块链也逐步走进公众视野,引起大众注意.本文用不到50行的Python代码构建最小的数据区块链,简单介绍了区块链去中心化的结构与其实现原理. 尽管一些人 ...

  8. Postgresql 数据库错误修复v0.1

    PS. 查询\nebula_boh\logs\BOHInterfaceLog.log 日志, 一般数据库文件损坏的日志 有 “UncategorizedSQLException” 或 “zero pa ...

  9. LAMP安装教程

    LAMP环境配置安装注意安装步骤及说明事项. Linux + apache+mysql+php 附件: 1. 访问ftp报错 解决: 关闭selinux vi  /etc/selinux/config ...

  10. chat.css

    *, *:before, *:after { box-sizing: border-box;}body, html { height: 100%; overflow: hidden;}body, ul ...