Python2.7字符编码详解

Python2.7字符编码详解

目录

Python2.7字符编码详解
声明
一. 字符编码基础
1.1 抽象字符清单(ACR)
1.2 已编码字符集(CCS)
1.3 字符编码格式(CEF)
1.3.1 ASCII(初创)
1.3.2 MBCS/DBCS/ANSI(本地化)
1.3.3 Unicode(国际化)
1.4 字符编码方案(CES)
1.5 中文字符乱码(Mojibake)
1.5.1 未指定编码格式
1.5.2 错误指定编码格式
1.5.3 过度指定编码格式
1.5.4 解决方案
二. Python2.7字符编码
2.1 str和unicode类型
2.2 源码字符串常量(Literals)
2.3 读写Unicode数据
2.4 Unicode文件名
2.5 处理中文乱码
2.6 中文处理建议
三. 参考资料
Python2.7字符编码详解
标签: Python 字符编码

声明
本文主要介绍字符编码基础知识,以及Python2.7字符编码实践。
注意,文中关于Python字符编码的解释和建议适用于Python2.x版本,而不适用于3.x版本。
本文同时也发布于作业部落,阅读体验可能更好。

一. 字符编码基础
为明确概念,将字符集的编码模型分为以下4个层次:

抽象字符清单(Abstract Character Repertoire, ACR):
待编码文字和符号的无序集合,包括各国文字、标点、图形符号、数字等。
已编码字符集(Coded Character Set, CCS):
从抽象字符清单到非负整数码点(code point)集合的映射。
字符编码格式(Character Encoding Form, CEF):
从码点集合到指定宽度(如32比特整数)编码单元(code unit)的映射。
字符编码方案(Character Encoding Scheme, CES):
从编码单元序列集合(一个或多个CEF)到一个串行化字节序列的可逆转换。
1.1 抽象字符清单(ACR)
抽象字符清单可理解为无序的抽象字符集合。“抽象"意味着字符对象并非直接存在于计算机系统中,也未必是真实世界中具体的事物,例如"a"和"为”。抽象字符也不必是图形化的对象,例如控制字符"0宽度空格"(zero-width space)。

大多数字符编码的清单较小且处于"fixed"状态,即不再追加新的抽象字符(否则将创建新的清单);其他清单处于"open"状态,即允许追加新字符。例如,Unicode旨在成为通用编码,其字符清单本身是开放的,以便周期性的添加新的可编码字符。

1.2 已编码字符集(CCS)
已编码字符集是从抽象字符清单到非负整数(范围不必连续)的映射。该整数称为抽象字符被赋予的码点(code point,或称码位code position),该字符则称为已编码字符。注意,码点并非比特或字节,因此与计算机表示无关。码点的取值范围由编码标准限定,该范围称为编码空间(code space)。在一个标准中,已编码字符集也称为字符编码、已编码字符清单、字符集定义或码页(code page)。

在CCS中,需要明确定义已编码字符相关的任何属性。通常,标准为每个已编码字符分配唯一的名称,例如“拉丁小写字母A(LATIN SMALL LETTER A)”。当同一个抽象字符出现在不同的已编码字符集且被赋予不同的码点时,通过其名称可无歧义地标识该字符。但实际应用中厂商或其他标准组织未必遵循这一机制。Unicode/10646出现后,其通用性使得该机制近乎过时。

某些工作在CCS层的工业标准将字符集标准化(可能也包括其名称或其他属性),但并未将它们在计算机中的编码表示进行标准化。例如,东亚字符标准GB2312-80(简体中文)、CNS 11643(繁体中文)、JIS X 0208(日文),KS X 1001(韩文)。这些标准使用与之独立的标准进行字符编码的计算机表示,这将在CEF层描述。

1.3 字符编码格式(CEF)
字符编码格式是已编码字符集中的码点集合到编码单元(code unit)序列的映射。编码单元为整数,在计算机架构中占据特定的二进制宽度,例如7比特、8比特等(最常用的是8/16/32比特)。编码格式使字符表示为计算机中的实际数据。

编码单元的序列不必具有相同的长度。序列具有相同长度的字符编码格式称为固定宽度(或称等宽),否则称为可变宽度(或称变长)。固定宽度的编码格式示例如下:
在这里插入图片描述
可变宽度的编码格式示例如下:

一个码点未必对应一个编码单元。很多编码格式将一个码点映射为多个编码单元的序列,例如微软码页932(日文)或950(繁体中文)中一个字符编码为两个字节。然而,码点到编码单元序列的映射是唯一的。

除东亚字符集外,所有传统字符集的编码空间都未超出单字节范围,因此它们通常使用相同的编码格式(对此不必区分码点和编码单元)。

某些字符集可使用多种编码格式。例如,GB2312-80字符集可使用GBK编码、ISO 2022编码或EUC编码。此外,有的编码格式可用于多种字符集,例如ISO 2022标准。ISO 2022为其支持的每个特定字符集分配一个特定的转义序列(escape sequence)。默认情况下,ISO 2022数据被解释为ASCII字符集;遇到任一转义序列时则以特定的字符集解释后续的数据,直到遇到一个新的转义序列或恢复到默认状态。ISO 2022标准旨在提供统一的编码格式,以期支持所有字符集(尤其是中日韩等东亚文本)。但其数据解释的控制机制相当复杂,且缺点很多,仅在日本使用普遍。

Unicode标准并未依照惯例,将每个字符直接映射为特定模式的编码比特序列。相反地,Unicode先将字符映射为码点,再将码点以各种方式各种编码单元编码。通过将CCS和CEF分离,Unicode的编码格式更为灵活(如UCS-X和UTF-X)。

以下详细介绍中文编码时常见的字符集及其编码格式。为符合程序员既有概念,此处并未严格区分CCS与CEF。但应认识到,ASCII/EASCII和GB2312/GBK/GB18030既是CCS也是CEF;区位码和Unicode是CCS;EUC-CN/ISO-2022-CN/HZ、UCS-2/UCS-4、UTF-8/UTF-16/UTF-32是CEF。

注意,中文编码还有交换码、输入码、机内码、输出码等概念。交换码又称国标码,用于汉字信息交换,即GB2312-80(区位码加0x20)。输入码又称外码,即使用英文键盘输入汉字时的编码,大体分为音码、形码、数字码和音形码四类。例如,汉字"肖"用拼音输入时外码为xiao,用区位码输入时为4804,用五笔字型输入时为IEF。机内码又称内码或汉字存储码,即计算机操作系统内部存储、处理和交换汉字所用的编码(GB2312/GBK)。尽管同一汉字的输入码有多种,但其内码相同。输出码又称字型码,即根据汉字内码找到字库中的地址,再将其点阵字型在屏幕上输出。

早期Windows系统默认的内码与语言相关,英文系统内码为ASCII,简体中文系统内码为GB2312或GBK,繁体中文系统内码为BIG5。Windows NT+内核则采用Unicode编码,以便支持所有语种字符。但由于现有的大量程序和文档都采用某种特定语言的编码,因此微软使用码页适应各种语言。例如,GB2312码页是CP20936,GBK码页是CP936,BIG5码页是CP950。此时,"内码"的概念变得模糊。微软一般将缺省码页指定的编码称为内码,在特殊场合也称其内码为Unicode。

1.3.1 ASCII(初创)
1.3.1.1 ASCII
ASCII(American Standard Code for Information Interchange)为7比特编码,编码范围是0x00-0x7F,共计128个字符。ASCII字符集包括英文字母、阿拉伯数字、英式标点和控制字符等。其中,0x00-0x1F和0x7F为33个无法打印的控制字符。

ASCII编码设计良好,如数字和字母连续排列,数字对应其16进制码点的低四位,大小写字母可通过一个bit的翻转而相互转化,等等。初创标准的影响力如此之强,以致于后世所有广泛应用的编码标准都要兼容ASCII编码。

在Internet上使用时,ASCII的别名(不区分大小写)有ANSI_X3.4-1968、iso-ir-6、ANSI_X3.4-1986、ISO_646.irv:1991、ISO646-US、US-ASCII、IBM367、cp367和csASCII。

1.3.1.2 EASCII
EASCII扩展ASCII编码字节中闲置的最高位,即8比特编码,以支持其他非英语语言。EASCII编码范围是0x00-0xFF,共计256个字符。

不同国家对0x80-0xFF这128个码点的不同扩展,最终形成15个ISO-8859-X编码标准(X=111,1316),涵盖拉丁字母的西欧语言、使用西里尔字母的东欧语言、希腊语、泰语、现代阿拉伯语、希伯来语等。例如为西欧语言而扩展的字符集编码标准编号为ISO-8859-1,其别名为cp819、csISO、Latin1、ibm819、iso_8859-1、iso_8859-1:1987、iso8859-1、iso-ir-100、l1、latin-1。

ISO-8859-1标准中,0x00-0x7F之间与ASCII字符相同,0x80-0x9F之间是控制字符,0xA0-0xFF之间是文字符号。其字符集详见ASCII码表。在Windows记事本里,通过ALT+Latin1码点10进制值可输入相应字符。
ISO-8859-1编码空间覆盖单字节所有取值,在支持ISO-8859-1的系统中传输和存储其他任何编码的字节流都不会造成数据丢失。换言之,可将任何编码的字节流视为ISO-8859-1编码。因此,很多传输(如Java网络传输)和存储(如MySQL数据库)过程默认使用该编码。

注意,ISO-8859-X编码标准互不兼容。例如,0xA3在Latin1编码中代表英镑符号"£",在Latin2编码中则代表"Ł"(带斜线的大写L)。而且,这两个符号无法同时出现在一个文件内。

ASCII和EASCII均为单字节编码(Single Byte Character System, SBCS),即使用一个字节存放一个字符。只支持ASCII码的系统会忽略每个字节的最高位,只认为低7位是有效位。

1.3.2 MBCS/DBCS/ANSI(本地化)
由于单字节能表示的字符太少,且同时也需要与ASCII编码保持兼容,所以不同国家和地区纷纷在ASCII基础上制定自己的字符集。这些字符集使用大于0x80的编码作为一个前导字节,前导字节与紧跟其后的第二(甚至第三)个字节一起作为单个字符的实际编码;而ASCII字符仍使用原来的编码。以汉字为例,字符集GB2312/BIG5/JIS使用两个字节表示一个汉字,使用一个字节表示一个ASCII字符。这类字符集统称为ANSI字符集,正式名称为MBCS(Multi-Byte Chactacter Set,多字节字符集)或DBCS(Double Byte Charecter Set,双字节字符集)。在简体中文操作系统下,ANSI编码指代GBK编码;在日文操作系统下,ANSI编码指代JIS编码。

ANSI编码之间互不兼容,因此Windows操作系统使用码页转换表技术支持各字符集的显示问题,即通过指定的转换表将非Unicode的字符编码转换为同一字符对应的系统内部使用的Unicode编码。可在"区域和语言选项"中选择一个代码页作为非Unicode编码所采用的默认编码方式,如936为简体中文GBK,950为繁体中文Big5。但当信息在国际间交流时,仍无法将属于两种语言的文本以同一种ANSI编码存储和传输。

1.3.2.1 GB2312
GB2312为中国国家标准简体中文字符集,全称《信息交换用汉字编码字符集 基本集》,由中国国家标准总局于1980年发布,1981年5月1日开始实施。标准号是GB 2312—1980。

GB2312标准适用于汉字处理、汉字通信等系统之间的信息交换,通行于中国大陆地区及新加坡,简称国标码。GB2312标准共收录6763个简体汉字,其中一级汉字3755个,二级汉字3008个。此外,GB2312还收录数学符号、拉丁字母、希腊字母、日文平假名及片假名字母、俄语西里尔字母等682个字符。这些非汉字字符有些来自ASCII字符集,但被重新编码为双字节,并称为"全角"字符;ASCII原字符则称为"半角"字符。例如,全角a编码为0xA3E1,半角a则编码为0x61。

GB2312是基于区位码设计的。区位码将整个字符集分成94个区,每区有94个位。每个区位上只有一个字符,因此可用汉字所在的区和位来对其编码。

区位码中01-09区为特殊符号。16-55区为一级汉字,按拼音字母/笔形顺序排序;56-87区为二级汉字,按部首/笔画排序。10-15区及88-94区为未定义的空白区。

区位码是一个四位的10进制数,如1601表示16区1位,对应的字符是“啊”。Windows系统支持区位输入法,例如通过"中文(简体) - 内码"输入法小键盘输入1601可得到"啊",输入0528则得到"ゼ"。

区位码可视为已编码字符集,其编码格式可为EUC-CN(常用)、ISO-2022-CN(罕用)或HZ(用于新闻组)。ISO-2022-CN和HZ针对早期只支持7比特ASCII的系统而设计,且因为使用转义序列而存在诸多缺点。ISO-2022标准将区号和位号加上32,以避开ASCII的控制符区。而EUC(Extended Unix Code)基于ISO-2022区位码的94x94编码表,将其编码字节的最高位置1,以简化日文、韩文、简体中文表示。可见,EUC区(位) = 原始区(位)码 + 32 + 0x80 = 原始区(位)码 + 0xA0。这样易于软件识别字符串中的特定字节,例如小于0x7F的字节表示ASCII字符,两个大于0x7F的字节组合表示一个汉字。EUC-CN是GB2312最常用的表示方法,可认为通常所说的GB2312编码就指EUC-CN或EUC-GB2312。

综上,GB2312标准中每个汉字及符号以两个字节来表示。第一个字节称为高字节(也称区字节),使用0xA1-0xF7(将01-87区的区号加上0xA0);第二个字节称为低字节(也称位字节),使用0xA1-0xFE(将01-94加上 0xA0)。汉字区的高字节范围是0xB0-0xF7,低字节范围是0xA1-0xFE,占用码位72*94=6768。其中有5个空位是D7FA-D7FE。例如,汉字"肖"的区位码为4804,将其区号和位号分别加上0xA0得到0xD0A4,即为GB2312编码。汉字的GB2312编码详见GB2312简体中文编码表,也可通过汉字编码网站查询。

GB2312所收录的汉字已覆盖中国大陆99.75%的使用频率,但不包括人名、地名、古汉语等方面出现的生僻字。

1.3.2.2 GBK
GBK全称为《汉字内码扩展规范》 ,于1995年发布,向下完全兼容GB2312-1980国家标准,向上支持ISO 10646.1国际标准。该规范收录Unicode基本多文种平面中的所有CJK(中日韩)汉字,并包含BIG5(繁体中文)编码中的所有汉字。其编码高字节范围是0x81-0xFE,低字节范围是0x40-0x7E和0x80-0xFE,共23940个码位,收录21003个汉字和883个图形符号。

GBK码位空间可划分为以下区域:
在这里插入图片描述
注意,码位空间中的码位并非都已编码,例如0xA2E3和0xA2E4并未定义编码。

为扩展码位空间,GBK规定只要高字节大于0x7F就表示一个汉字的开始。但低字节为0x40-0x7E的GBK字符会占用ASCII码位,而程序可能使用该范围内的ASCII字符作为特殊符号,例如将反斜杠""作为转义序列的开始。若定位这些符号时未判断是否属于某个GBK汉字的低字节,就

#include "config.h" #define FOSC 22118400L //System frequency uint32_t baud=9600; //UART baudrate uint8_t RX_BUF[50]; uint8_t NUM_1=0; /************************************************************************ �� �� ���� ���ڳ�ʼ�� ���������� STC10L08XE ��Ƭ�����ڳ�ʼ������ ���غ����� none ����˵���� none **************************************************************************/ void UartIni(void) { SCON = 0x50; //8-bit variable UART TMOD = 0x20; //Set Timer1 as 8-bit auto reload mode TH1 = TL1 = -(FOSC/12/32/baud); //Set auto-reload vaule TR1 = 1; //Timer1 start run ES = 1; //Enable UART interrupt EA = 1; //Open master interrupt switch } /************************************************************************ ���������� ���ڷ���һ�ֽ����� ��ڲ����� DAT:�����͵����� �� �� ֵ�� none ����˵���� none **************************************************************************/ void UARTSendByte(uint8_t DAT) { ES = 0; TI=0; SBUF = DAT; while(TI==0); TI=0; ES = 1; } /************************************************************************ ���������� ���ڷ����ַ������� ��ڲ����� *DAT���ַ���ָ�� �� �� ֵ�� none ����˵���� API ���ⲿʹ�ã�ֱ�ۣ� **************************************************************************/ void PrintCom(uint8_t *DAT) { while(*DAT) { UARTSendByte(*DAT++); } } void Uart_Isr() interrupt 4 using 1 { if (RI) { RI=0; RX_BUF[NUM_1]=SBUF; NUM_1++; if(NUM_1>=49) NUM_1=0; if(NUM_1>=3) { if(RX_BUF[NUM_1]==0xF8&&RX_BUF[NUM_1-1]==0xF8&&RX_BUF[NUM_1-2]==0xF8) IAP_CONTR=0x60; } } } 什么意思
07-25
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值