一:什么是编码

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

  那么什么是明文呢,首先我们从一段信息说起,消息以人们可以理解,易懂的表示存在,我们把这个表示为明文(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. shell awk处理过滤100万条数据

    背景: 100万条数据.格式如下: ID 地址 1895756546931805 安徽省六安市裕安区固镇镇佛俺村柳树队5758 安徽省蒙城县岳坊镇胡寨村小组小胡寨庄6号 183494167409969 ...

  2. Postman SMTP 存在跨站脚本(XSS)漏洞,请换用Post SMTP Mailer/Email Log

    Postman SMTP 是一个安装量超过10W的WordPress插件,但是已经2年多没有更新,2017年6月29日,被发现存在跨站脚本(XSS)漏洞(查看详情),并且作者一直没有更新,所以被从Wo ...

  3. vb越界

    想起来一个项目当中,遇到了一个问题,就是老是显示数据溢出. 后来查查查,发现是由于vb的特性造成的.例如cbyte()函数.此函数()里面的数据运算也不能超过cbyte的范围,不然就回发生溢出问题.

  4. GodMode

    将“GodMode.{ED7BA470-8E54-465E-825C-99712043E01C}”(不含引号)复制过去,保存即可.

  5. Product and Sum in Category Theory

    Even if you are not a functional programmer, the notion of product type should be familiar to you, e ...

  6. 《设计模式》学习&理解&总结

    教程地址:http://www.runoob.com/design-pattern/design-pattern-tutorial.html 教程书籍:<Android 设计模式解析与实战> ...

  7. 第78节:Java中的网络编程(上)

    第78节:Java中的网络编程(上) 前言 网络编程涉及ip,端口,协议,tcp和udp的了解,和对socket通信的网络细节. 网络编程 OSI开放系统互连 网络编程指IO加网络 TCP/IP模型: ...

  8. php--include 、require

    一.include .require 定义:包含并运行指定文件 问题:查询了这两个语言结构的资料,有人说,什么require  先执行,什么include后执行. 思考:我觉得官方文档已经解释的很清楚 ...

  9. 音频处理库—librosa的安装与使用

    序言 Librosa是一个用于音频.音乐分析.处理的python工具包,一些常见的时频处理.特征提取.绘制声音图形等功能应有尽有,功能十分强大.本文主要介绍librosa的安装与使用方法. 一.lib ...

  10. ES6的Promise

    推荐一下我觉得不错关于Promise的好文章,通俗易懂 说起ES6的Promise就要提及一下JQ的$.when()方法,两者基本相同 面试的时候经常会问Promise,如果同学们能在回答Promis ...