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 类型再运算。

参考资料

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/566729.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于模型的系统工程MBSE软件工具(ModelCoder)

我们一直致力于提供给航空航天制造商一套全数字的MBSE建模与仿真优化解决方案——基于模型的系统工程MBSE软件工具(ModelCoder)。我们的仿真验证技术可用于开发高复杂度和高保真度的模型,对飞机发动机,飞机的飞控进行预测性的虚拟…

面向航空航天工业领域的基于模型的仿真验证工具SkyEye

我们一直致力于提供给航空航天制造商一套全数字的优化方案——面向航空航天工业领域的基于模型的仿真验证工具SkyEye。我们的仿真验证技术可用于开发高复杂度和高保真度的模型,对发动机,飞机的飞控进行预测性的虚拟验证和测试。我们能够准确地进行全数字…

高性能高可靠性的全数字嵌入式仿真测试软件SkyEye

随着科技的发展,系统工程的设计体量逐渐庞大起来,尤其是对于轨道交通、航空航天、核电站等安全关键领域中,如何在复杂度逐年变大的同时保证其安全性和可靠性,是近年来各大公司需要研究的课题。最近比较火热的基于模型的系统工程&a…

二元一次函数最值问题_初二上学期,一次函数方案设计最值问题,两类题目解题思路不一样...

方案设计问题在一元一次方程实际问题中有所接触,在一次函数实际应用题中也有。一次函数中的方案设计问题,常与一次函数的性质、不等式(组)、方程组等知识点相结合,这类题目一旦掌握解题方法,难度不是很大。本篇文章主要介绍一次函…

rabiitmq卸载_RabbitMQ安装方式及常用命令

在ubuntu系统中安装rabbitmq# wget http://www.rabbitmq.com/releases/rabbitmq-server/v3.6.6/rabbitmq-server_3.6.6-1_all.deb# dpkg -i rabbitmq-server_3.6.6-1_all.deb如果提示依赖其他的包,执行如下命令安装依赖包# apt-get -f install然后# dpkg -i rabbitm…

高性能全数字嵌入式仿真测试软件SkyEye支持多达70余种核心

全数字仿真平台作为工业领域不可缺少的重要软件之一,除了可以与MATLAB或者Simulink集成外,还支持哪些优秀的功能?在了解新一代全数字仿真平台SkyEye之前,先来学习一下什么是全数字仿真平台。 什么是全数字仿真平台 全数字仿真平…

dalsa线扫相机调试文档_线阵相机调试文档

1.相机型号参数相机:线16k CL分辨率:16384 x 1像素大小:3.52 μm x 3.52 μm麦克斯行费率:48 千赫镜头安装(螺纹):M72 x 1产品编号:LA-CM-16K05A-xx-R注:现场采用的相机型号即为上表1.1型号参数…

SystemC 代码添加和测试方法

1.启动流程 在 code/utils/ 下添加 new_systemc 相关代码,启动流程如下: 2.调用关系 3.地址映射 假设有两个 systemc 设备:device1 和 device2,device1 的内存地址映射区域为 0x20000x2fff,device2 的内存映射区域为 …

channelsftp的put_JSch - Java实现的SFTP(文件上传详解篇)

public void put(String src, String dst)将本地文件名为src的文件上传到目标服务器,目标文件名为dst,若dst为目录,则目标文件名将与src文件名相同。采用默认的传输模式:OVERWRITEpublic void put(String src, String dst, int mo…

支持多达70余种嵌入式核心的嵌入式仿真软件SkyEye

SkyEye 介绍 SkyEye,中文全称天目全数字实时仿真软件,应用软件仿真技术,逼真地模拟出被测软件的物理环境。用图形化方式构建虚拟目标系统,有效降低了硬件工程师和软件工程师之间的沟通成本,软件工程师可以不依赖硬件工…

xxljob默认登录_xxl-job安装部署整理

xxl-job github源码地址:https://github.com/xuxueli/xxl-jobxxl-job 官方文档:https://www.xuxueli.com/xxl-job/#系统组成调度模块(调度中心):负责管理调度信息,按照调度配置发出调度请求,自身不承担业务代码。调度系…

嵌入式仿真平台SkyEye的覆盖率分析

随着嵌入式系统也越来越复杂,功能迭代越来越多,代码中就可能就会存在部分无用代码,或者在执行过程中无法测试覆盖的分支,这可能就会给软件带来很大的漏洞,严重降低软件的可靠性。因此,需要一个能够动态分析…

access重复数据累计_小程序·云开发之数据库自动备份丨云开发101

小程序云开发之数据库自动备份数据是无价的,我们通常会把重要的业务数据存放在数据库中,并需要对数据库做定时的自动备份工作,防止数据异常丢失,造成无法挽回的损失。小程序云开发提供了方便的云数据库供我们直接使用,…

嵌入式系统实时仿真解决方案SkyEye

SkyEye介绍 SkyEye,中文全称天目全数字实时仿真软件,应用软件仿真技术,逼真地模拟出被测软件的物理环境。用图形化方式构建虚拟目标系统,有效降低了硬件工程师和软件工程师之间的沟通成本,软件工程师可以不依赖硬件工…

read函数头文件 window_of_property_read_string 剖析

前言今天在一个群里面看到的一个朋友提交,说of_property_read_string 这个函数有两个定义,到底是用了哪个呢?所以这篇文章就说下这个函数。函数引用的头文件引用的头文件位置在kernel-4.4includelinuxof.h其中一个是extern int of_property_r…

全数字实时仿真平台SkyEye的同步数据流语言可信编译器的构造

随着计算机控制系统在人们生活中的普及,软件自身的可靠性也越来越受到重视.在航空、高铁、核电及军事等高安全要求领域的软件系统——安全关键系统(safety-critical system,简称SCS)更是受到高度的重视.而随着软件系统的复杂度越来越高,软件系统的安全性保证也变得越来越困难.这…

div html 下边加横线_HTML的组成部分、DIV+CSS布局

HTML的组成部分dtd部分:文档类型说明,声明版本、标准header部分:给机器看的body部分:给人看的CSS控制div显示是一个块级元素。这意味着它的内容自动地开始一个新行。实际上,换行是 固有的唯一格式表现。可以通过 的 cl…

国产主可控的嵌入式仿真测试软件SkyEye与可信编译器L2C的核心翻译介绍

为了满足国内某安全攸关领域的需求, L2C编译器的开发始于2010年9月, 其目标是设计实现一个经过形式化验证的可信编译器, 其源语言是面向领域的同步数据流语言Lustre*(Lustre语言的一个变种, 参考下一节), 目标语言是C, 最终可用作相关领域数字化仪控系统的安全级代码生成器.国产…

python 经纬度计算距离公式_SymPy符号计算-让Python帮我们推公式

作者: 阿凯Email: xingshunkaiqq.com概要像我这种粗心的小孩, 在推导一些复杂的公式(尤其是矩阵运算)的时候, 经常容易算错数, 一步推错,步步错。万能的Python有什么方法可以帮助我们节省时间, 减少出错率呢? 有一个包叫做SymPy, 它可以帮我们自动的进行符号化计算…

支持国产处理器仿真的全数字实时仿真平台SkyEye与可信编译器L2C的核心翻译步骤

1、核心翻译步骤示例 本节我们以第2节提到的Lustre语言的主要特性为线索来解释L2C在翻译过程中的关键节点是如何处理的, 并以图 1的实例来解释Lustre程序是如何被一步步地翻译到Clight语言的. 1.1 数据流并发性 Lustre程序具有数据流并发性, 而Clight程序却是串行执行的.因此…