python的字符编码叙述_Python: 熟悉又陌生的字符编码
字符编码是计算机编程中不可回避的问题,不管你用 Python2 还是 Python3,亦或是 C++, Java 等,我都觉得非常有必要厘清计算机中的字符编码概念。本文主要分以下几个部分介绍:
基本概念
常见字符编码简介
Python 的默认编码
Python2 中的字符类型
UnicodeEncodeError & UnicodeDecodeError 根源
基本概念
字符(Character)
在电脑和电信领域中,字符是一个信息单位,它是各种文字和符号的总称,包括各国家文字、标点符号、图形符号、数字等。比如,一个汉字,一个英文字母,一个标点符号等都是一个字符。
字符集(Character set)
字符集是字符的集合。字符集的种类较多,每个字符集包含的字符个数也不同。比如,常见的字符集有 ASCII 字符集、GB2312 字符集、Unicode 字符集等,其中,ASCII 字符集共有 128 个字符,包含可显示字符(比如英文大小写字符、阿拉伯数字)和控制字符(比如空格键、回车键);GB2312 字符集是中国国家标准的简体中文字符集,包含简化汉字、一般符号、数字等;Unicode 字符集则包含了世界各国语言中使用到的所有字符,
字符编码(Character encoding)
字符编码,是指对于字符集中的字符,将其编码为特定的二进制数,以便计算机处理。常见的字符编码有 ASCII 编码,UTF-8 编码,GBK 编码等。一般而言,字符集和字符编码往往被认为是同义的概念,比如,对于字符集 ASCII,它除了有「字符的集合」这层含义外,同时也包含了「编码」的含义,也就是说,ASCII 既表示了字符集也表示了对应的字符编码。
下面我们用一个表格做下总结:
概念
概念描述
举例
字符
一个信息单位,各种文字和符号的总称
‘中’, ‘a', ‘1', '$', ‘¥’, ...
字符集
字符的集合
ASCII 字符集, GB2312 字符集, Unicode 字符集
字符编码
将字符集中的字符,编码为特定的二进制数
ASCII 编码,GB2312 编码,Unicode 编码
字节
计算机中存储数据的单元,一个 8 位(bit)的二进制数
0x01, 0x45, ...
常见字符编码简介
常见的字符编码有 ASCII 编码,GBK 编码,Unicode 编码和 UTF-8 编码等等。这里,我们主要介绍 ASCII、Unicode 和 UTF-8。
ASCII
计算机是在美国诞生的,人家用的是英语,而在英语的世界里,不过就是英文字母,数字和一些普通符号的组合而已。
在 20 世纪 60 年代,美国制定了一套字符编码方案,规定了英文字母,数字和一些普通符号跟二进制的转换关系,被称为 ASCII (American Standard Code for Information Interchange,美国信息互换标准编码) 码。
比如,大写英文字母 A 的二进制表示是 01000001(十进制 65),小写英文字母 a 的二进制表示是 01100001 (十进制 97),空格 SPACE 的二进制表示是 00100000(十进制 32)。
Unicode
ASCII 码只规定了 128 个字符的编码,这在美国是够用的。可是,计算机后来传到了欧洲,亚洲,乃至世界各地,而世界各国的语言几乎是完全不一样的,用 ASCII 码来表示其他语言是远远不够的,所以,不同的国家和地区又制定了自己的编码方案,比如中国大陆的 GB2312 编码 和 GBK 编码等,日本的 Shift_JIS 编码等等。
虽然各个国家和地区可以制定自己的编码方案,但不同国家和地区的计算机在数据传输的过程中就会出现各种各样的乱码(mojibake),这无疑是个灾难。
怎么办?想法也很简单,就是将全世界所有的语言统一成一套编码方案,这套编码方案就叫 Unicode,它为每种语言的每个字符设定了独一无二的二进制编码,这样就可以跨语言,跨平台进行文本处理了,是不是很棒!
Unicode 1.0 版诞生于 1991 年 10 月,至今它仍在不断增修,每个新版本都会加入更多新的字符,目前最新的版本为 2016 年 6 月 21 日公布的 9.0.0。
Unicode 标准使用十六进制数字,而且在数字前面加上前缀 U+,比如,大写字母「A」的 unicode 编码为 U+0041,汉字「严」的 unicode 编码为 U+4E25。更多的符号对应表,可以查询 unicode.org,或者专门的汉字对应表。
UTF-8
Unicode 看起来已经很完美了,实现了大一统。但是,Unicode 却存在一个很大的问题:资源浪费。
为什么这么说呢?原来,Unicode 为了能表示世界各国所有文字,一开始用两个字节,后来发现两个字节不够用,又用了四个字节。比如,汉字「严」的 unicode 编码是十六进制数 4E25,转换成二进制有十五位,即 100111000100101,因此至少需要两个字节才能表示这个汉字,但是对于其他的字符,就可能需要三个或四个字节,甚至更多。
这时,问题就来了,如果以前的 ASCII 字符集也用这种方式来表示,那岂不是很浪费存储空间。比如,大写字母「A」的二进制编码为 01000001,它只需要一个字节就够了,如果 unicode 统一使用三个字节或四个字节来表示字符,那「A」的二进制编码的前面几个字节就都是 0,这是很浪费存储空间的。
为了解决这个问题,在 Unicode 的基础上,人们实现了 UTF-16, UTF-32 和 UTF-8。下面只说一下 UTF-8。
UTF-8 (8-bit Unicode Transformation Format) 是一种针对 Unicode 的可变长度字符编码,它使用一到四个字节来表示字符,例如,ASCII 字符继续使用一个字节编码,阿拉伯文、希腊文等使用两个字节编码,常用汉字使用三个字节编码,等等。
因此,我们说,UTF-8 是 Unicode 的实现方式之一,其他实现方式还包括 UTF-16(字符用两个或四个字节表示)和 UTF-32(字符用四个字节表示)。
Python 的默认编码
Python2 的默认编码是 ascii,Python3 的默认编码是 utf-8,可以通过下面的方式获取:
Python2
Python 2.7.11 (default, Feb 24 2016, 10:48:05)
[GCC 4.2.1 Compatible Apple LLVM 7.0.2 (clang-700.1.81)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.getdefaultencoding()
'ascii'
Python3
Python 3.5.2 (default, Jun 29 2016, 13:43:58)
[GCC 4.2.1 Compatible Apple LLVM 7.3.0 (clang-703.0.31)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.getdefaultencoding()
'utf-8'
Python2 中的字符类型
Python2 中有两种和字符串相关的类型:str 和 unicode,它们的父类是 basestring。其中,str 类型的字符串有多种编码方式,默认是 ascii,还有 gbk,utf-8 等,unicode 类型的字符串使用 u'...' 的形式来表示,下面的图展示了 str 和 unicode 之间的关系:
两种字符串的相互转换概括如下:
把 UTF-8 编码表示的字符串 'xxx' 转换为 Unicode 字符串 u'xxx' 用 decode('utf-8') 方法:
>>> '中文'.decode('utf-8')
u'\u4e2d\u6587'
把 u'xxx' 转换为 UTF-8 编码的 'xxx' 用 encode('utf-8') 方法:
>>> u'中文'.encode('utf-8')
'\xe4\xb8\xad\xe6\x96\x87'
UnicodeEncodeError & UnicodeDecodeError 根源
用 Python2 编写程序的时候经常会遇到 UnicodeEncodeError 和 UnicodeDecodeError,它们出现的根源就是如果代码里面混合使用了 str 类型和 unicode 类型的字符串,Python 会默认使用 ascii 编码尝试对 unicode 类型的字符串编码 (encode),或对 str 类型的字符串解码 (decode),这时就很可能出现上述错误。
下面有两个常见的场景,我们最好牢牢记住:
在进行同时包含 str 类型和 unicode 类型的字符串操作时,Python2 一律都把 str 解码(decode)成 unicode 再运算,这时就很容易出现 UnicodeDecodeError。
让我们看看例子:
>>> s = '你好' # str 类型, utf-8 编码
>>> u = u'世界' # unicode 类型
>>> s + u # 会进行隐式转换,即 s.decode('ascii') + u
Traceback (most recent call last):
File "", line 1, in
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128)
为了避免出错,我们就需要显示指定使用 'utf-8' 进行解码,如下:
>>> s = '你好' # str 类型,utf-8 编码
>>> u = u'世界'
>>>
>>> s.decode('utf-8') + u # 显示指定 'utf-8' 进行转换
u'\u4f60\u597d\u4e16\u754c' # 注意这不是错误,这是 unicode 字符串
如果函数或类等对象接收的是 str 类型的字符串,但你传的是 unicode,Python2 会默认使用 ascii 将其编码成 str 类型再运算,这时就很容易出现 UnicodeEncodeError。
让我们看看例子:
>>> u_str = u'你好'
>>> str(u_str)
Traceback (most recent call last):
File "", line 1, in
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)
在上面的代码中,u_str 是一个 unicode 类型的字符串,由于 str() 的参数只能是 str 类型,此时 Python 会试图使用 ascii 将其编码成 ascii,也就是:
u_str.encode('ascii') // u_str 是 unicode 字符串
上面将 unicode 类型的中文使用 ascii 编码转,肯定会出错。
再看一个使用 raw_input 的例子,注意 raw_input 只接收 str 类型的字符串:
>>> name = raw_input('input your name: ')
input your name: ethan
>>> name
'ethan'
>>> name = raw_input('输入你的姓名:')
输入你的姓名: 小明
>>> name
'\xe5\xb0\x8f\xe6\x98\x8e'
>>> type(name)
>>> name = raw_input(u'输入你的姓名: ') # 会试图使用 u'输入你的姓名'.encode('ascii')
Traceback (most recent call last):
File "", line 1, in
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)
>>> name = raw_input(u'输入你的姓名: '.encode('utf-8')) #可以,但此时 name 不是 unicode 类型
输入你的姓名: 小明
>>> name
'\xe5\xb0\x8f\xe6\x98\x8e'
>>> type(name)
>>> name = raw_input(u'输入你的姓名: '.encode('utf-8')).decode('utf-8') # 推荐
输入你的姓名: 小明
>>> name
u'\u5c0f\u660e'
>>> type(name)
再看一个重定向的例子:
hello = u'你好'
print hello
将上面的代码保存到文件 hello.py,在终端执行 python hello.py 可以正常打印,但是如果将其重定向到文件 python hello.py > result 会发现 UnicodeEncodeError。
这是因为:输出到控制台时,print 使用的是控制台的默认编码,而重定向到文件时,print 就不知道使用什么编码了,于是就使用了默认编码 ascii 导致出现编码错误。
应该改成如下:
hello = u'你好'
print hello.encode('utf-8')
这样执行 python hello.py > result 就没有问题。
小结
UTF-8 是一种针对 Unicode 的可变长度字符编码,它是 Unicode 的实现方式之一。
Unicode 字符集有多种编码标准,比如 UTF-8, UTF-7, UTF-16。
在进行同时包含 str 类型和 unicode 类型的字符串操作时,Python2 一律都把 str 解码(decode)成 unicode 再运算。
如果函数或类等对象接收的是 str 类型的字符串,但你传的是 unicode,Python2 会默认使用 ascii 将其编码成 str 类型再运算。
参考资料
python的字符编码叙述_Python: 熟悉又陌生的字符编码相关推荐
- python中土耳其编码范围_python中的土耳其语字符
我正在使用Twitter API,但是关于土耳其语字符的编码有几个问题.这是我正在使用的代码: # -*- coding: cp1254 -*- import sys import csv impor ...
- python中怎么统计英文字符的个数_python怎样实现字符串中字符分类及个数统计
python怎样实现字符串中字符分类及个数统计 发布时间:2020-11-20 17:31:18 来源:亿速云 阅读:105 作者:小新 小编给大家分享一下python怎样实现字符串中字符分类及个数统 ...
- python基础编码规范_Python语言的基本语法和编码规范.doc
Python 语言的基本语法和编码规范 Python 编程教程教师 : 工作 :Python 语言的基本语法和编码标 准课程描述本章将介绍 Python 语言的基本语法和编码标准,重点介 绍 Pyth ...
- python中unicode编码表_Python中的字符串操作和编码Unicode详解
本文主要给大家介绍了关于 Python中的字符串操作和编码Unicode的一些知识,下面话不多说,需要的朋友们下面来一起学习吧. 字符串类型 str:Unicode字符串.采用''或者r''构造的字符 ...
- python获取文件字节数_python关于文件操作中的字符个数和字节数
记得刚开始学习python文件操作写文件的时候有个问题,很奇怪.最后知道了就是字节数的原因. 我们先来看个例子. 新建个文件存为utf-8命名为0117utf-8.txt记得去掉BOM头. 我们用r+ ...
- python统计字符频次_Python 统计长字符串中字符频次
以下笔记是我在 xue.cn 学习群之数据分析小组所整理分享的心得.相关背景是:我选择中文词频统计案例作为考察大家python基础功掌握程度. 通过<Python读取文件内容为字符串的方法> ...
- python 3.x版本的默认编码是_Python 3.x默认使用的编码是_
Python 3.x默认使用的编码是_ 答:UTF-8 X 线平片正常肺门阴影的最主要解剖结构是 答:肺动脉 . 肺静脉 <春秋>属于"六籍"之一.() 答:√ 中国大 ...
- python输出值报错_python:内建函数(一)数值相关、编码转换、help等
数值相关:int.abs.round.pow 输入输出:input.print 对象帮助:help.id 字符串编码转换函数:ord.chr 返回某个对象的所有属性的字符串列表:dir 1.int(x ...
- python笔记手写照片_Python笔记-将图片转换为字符画
[功能] 将jpg图片转换为字母画字符画( python 3.7版本下调试成功) [特点] 1.图片可默认位置,或者手工输入指定图片名 2.输出字符画高度可以设置,默认为60行 图片转字符画程序.jp ...
最新文章
- 《少年先疯队》第九次团队作业:Beta冲刺第二天
- 程序员的乐趣,生成自定义二维码,5 行 Python 代码就搞定
- SMS部署操作系统后记
- 关爱程序员,从产品经理做起!
- Linux 软件包管理常用命令 -- yum
- linux nload_Linux nload命令
- android studio sqlite操作代码片段
- VS调试按钮和运行按钮无法使用
- 获取Bootcamp 6 下载地址(mac装win10)
- Idea中jrebel激活码
- 一文告诉你 K8s PR (Pull Request) 怎样才能被 merge?
- mysql 经纬度 索引_转:mysql根据经纬度查找排序
- 家里Wifi网速突然变慢,一招瞬间提速
- 软件本身呢对shellcode 检查 SEH Exploit学习
- 2018第一届世界区块链大会:14场实力演讲+3场专题讨论精彩绝伦
- 解决一个MySQL登录报ERROR 2002 (HY000)错的问题
- Xbox 负责人对谈微软 CEO:为什么微软选择全力押注游戏业务
- 这样去求职,很少有公司能拒绝你
- IDEA如何远程断点调试jar包
- 欧路词典如何导入html,欧路词典怎么添加词库 管理词库的方法介绍
热门文章
- @JsonProperty注解解析
- Redis的内部运作机制——Redis详解
- Github PageHelper 原理解析
- Java番外篇2——jdk8新特性
- postman怎么不登陆使用_最新百度云不限速,免安装、免登陆、不限速,打开网站就能使用...
- 嵌入式linux组件,嵌入式Linux系统的几大组件!
- java http url 编码_Java中的HTTP URL地址编码
- from mysql partition select_玩转select条件查询,避免踩坑
- java 皮鞋_java反射
- Redis 实用技术——Pipeline