这篇文章将介绍Unicode编码的相关知识以及Python中Unicode编码的相关内容。
为了讲清楚这个问题,我们从计算机的字节及字符编码开始说起。
字节(Byte)是计算机信息技术中用于计量存储容量的一种单位,通常情况下,一个字节等于8位(bit),1位可以表示为二进制中的0或1。
在很多计算机语言中,字节(Byte)也是一种数据类型,用于存储字符。
在不同的字符编码方式中,一个字符占用的字节数量可能不同。如在ASCII编码方式下,用一个字节来存储1个字符。
一个字节共8位,对应的无符号二进制数可以有256种(即28种)情形(0~255,最大数:28-1),如果用一个二进制数表示一个字符的话,那么最多可以表示256个不同字符。
为了便于在计算机中进行存储和传递信息,在计算机技术中,将每个字符(包括控制字符,如回车、换行等)都分配唯一一个整型数字与其对应。如ASCII(American Standard Code for Information Interchange,美国信息交换标准码)使用8位二进制数对字符(包括字母、数字、标点符号、控制字符及其它符号)进行编码。因为八位的二进制数可以有256种数位(0和1)组合,最多能对256个字符进行编码,这种情况下对于处理英文信息是完全够用的,但是随着计算机在全世界的普及使用,这种编码方式已不足来处理更多的字符信息了,如我们常用的基本汉字就有三千多个,而ASCII编码方式最多能为256个字符编码,显然这种编码方式远远不够用的,因此,我国随后推出了汉字区位编码方式,GB2312,GBK以及为处理繁体字设计的Big5等。
不同的编码方式可能存在着冲突,即某一个编码在不同的编码方式中表示不同的字符,这为信息交换又带来了困难,因此后来人们设计了能够全球统一使用的Unicode编码方式。
Unicode一般称统一码,现已成为计算机领域的业界标准,它为每种语言的每个字符或符号分配了统一且唯一的二进制码,以满足跨语言、跨平台进行文本转换和处理的要求(来自百度百科)。
Unicode为每个字符或符号分配了唯一的一个称为码点(code point)或码位的整型数字。其范围从0到 0x10FFFF,通常以对应的十六进制进行表示。
Unicode规定了多种字符编码方式,如UTF-8、UTF-16、UTF-32等。
UTF是Unicode Transformation Format(统一码转换格式)的缩写。
不同的编码方式每个字符占用的字节数不尽相同。对字符对应的码点值进行编码时的最小字节单元称为码元(code unit,编码单元或代码单元)。UTF-8采用8位的单字节码元,UTF-16采用的16位的双字节码元,UTF-32是采用的32位的四字节码元。
最初Unicode只有UTF-16一种编码方式,UTF-8和UTF-32是后来发展起来的编码方式。
UTF-8编码方式是目前使用最广泛的一种编码方式。UTF-8使用的是8位单字节码元编码方式,但并非所有的字符都采用1个码元来编码,其编码序列可能为1~4个字节或更长。如英文字符仍占1个字节,而汉字占用3个字节来存储。
在具体实现中,UTF-8首字节用于识别编码的字节数。其规则为:除单字节编码以0开头外,多字节编码首字节1的个数用于判断编码后的字节长度,然后紧接着以数字0作为终结标志,除首字节外,多字节编码的后续字节都以10开头。
UTF-8使用变长字节来编码能够节省空间,易于扩展,且与已有的ASCII兼容。
UTF-16和UTF-32采用固定长度的编码方式也能够对全球语言的字符或符号进行编码,但不管是西文还是像亚洲的中日韩都使用统一的长度来存储,相对来说比较浪费空间。
再回到Python中对字符的编码方式上来。Python中默认采用UTF-8的编码方式。在Python中,字符串就是Unicode码点的序列,为有效存储字符,这些码点被转换成字节序列。这个过程被称为编码过程(encode)。
在Python中可以使用encode()函数将字符从一种编码方式转换成另外一种编码方式。关于该函数将在随后的文章中进行详细介绍,这里仅给出几个例子。
s = "武林网VEVB"
su = s.encode()
print('原字符串为:', s)
print('编码后的字符串为:', su)
其输出结果如下:
原字符串为: 武林网VEVB
编码后的字符串为: b'/xe7/xbf/x94/xe5/xae/x87/xe4/xba/xadIT/xe4/xb9/x90/xe5/x9b/xad'
从输出结果来看,编码后的字符串前有一个字母"b",表示字符串以字节的形式进行存储。因为汉字占用3个字节,所以输出时,汉字被转换成以/x开始的16进制形式,且有15个之多。而英文字母仍然原样输出。
Python中unicodedata模块中定义了所有unicode字符的属性。该模块中定义了一系列的函数来处理与unicode有关的问题。下面简单介绍这些函数的含义及使用方法。
(1)unicodedata.bidirectional(chr)函数
该函数的作用是以字符串的形式返回分配给字符chr的双向类。如果没有定义这样的值,则返回一个空字符串。
世界上的大多数语言书写是从左到右的(Left-to-Right,LTR),但有些却是从右到左的(Right-to-Left,RTL),如阿拉伯语、希伯来语等。但在RTL中,数字的书写顺序或是嵌入到书写中的英文又是从左到右的,这样实际上,这些语言的书写文本表示出双向性,如果没有规范,则在计算机处理这些信息时可能会产生歧义。
Unicode中把字符方向性定义为四大类(强、弱、中性和显示格式),每类下又分为若干小类型。
强(Strong)性下定义了以下三个小类:
L:表示Left-to-Right,即从左到右阅读,Unicode字符库中LRM范围中的字符
R:表示Right-to-Left,即从右到左阅读,Unicode字符库中RLM范围中的字符
AL:表示Right-to-Left阿拉伯语,Unicode字符库中ALM范围中的字符;
弱性(Weak)下定义了以下几个小类:
EN:表示欧洲数字:European Number
ES:表示欧洲数字分隔符:European Number Separator,如加号和减号等。
ET:表示欧洲数字终止符,European Number Terminator,如温度符号,货币符号等
AN:阿拉伯数字,Arabic Number
CS:普通数字分隔符,Common Number Separator,如冒号、逗号,句号,不间断空格等。
NSM:非间距性标记,Nonspacing Mark,定义在Unicode字符库中的Mn或Me中的值。
BN:中立性边界符,Boundary Neutral,默认可忽略的、非字符和控制字符,非显式给出的其它类型。
中性(Neutral)下的分类有:
B:段落分隔符,Paragraph Separator
S:段内内容分隔符,Segment Separator,Tab
WS:空白,Whitespace,如空格,换行符等
ON:其它中性符号
其它内容,感兴趣的读者可以到unicode官方网站查阅。
bidirectional()函数可以给出一个字符的分类字符串,即上面给出的L、R、NSM等。
import unicodedata
print(unicodedata.bidirectional('A'))
print(unicodedata.bidirectional('8'))
print(unicodedata.bidirectional('{'))
print(unicodedata.bidirectional('+'))
print(unicodedata.bidirectional('※'))
print(unicodedata.bidirectional(u'/u0357'))
输出结果如下:
L
EN
ON
ES
ON
NSM
(2)unicodedata.category(chr)
该函数是以字符串的形式返回字符chr所属的基本分类。Unicode中对各个字符按以下类别分类。该函数的作用是返回该字符所属的类别。
Unicode中的字符可能属于下表所示的某一种类型。
类别 | 说明 |
---|---|
Lu |
字母,大写 |
Ll |
字母,小写 |
Lt |
字母,词首字母大写 |
Lm |
字母,修饰符 |
Lo |
字母,其他 |
Mn |
标记,非间距 |
Mc |
标记,间距组合 |
Me |
标记,封闭 |
Nd |
数字,十进制数 |
Nl |
数字,字母 |
No |
数字,其他 |
Pc |
标点,连接符 |
Pd |
标点,短划线 |
Ps |
标点,开始 |
Pe |
标点,结束 |
Pi |
标点,前引号(根据用途可能表现为类似 Ps 或 Pe) |
Pf |
标点,后引号(根据用途可能表现为类似 Ps 或 Pe) |
Po |
标点,其他 |
Sm |
符号,数学 |
Sc |
符号,货币 |
Sk |
符号,修饰符 |
So |
符号,其他 |
Zs |
分隔符,空白 |
Zl |
分隔符,行 |
Zp |
分隔符,段落 |
Cc |
其他,控制 |
Cf |
其他,格式 |
Cs |
其他,代理项 |
Co |
其他,私用 |
Cn |
其他,未赋值(不存在任何字符具有此属性) |
下面举几个例子:
import unicodedata
print(unicodedata.category('A'))
print(unicodedata.category('a'))
print(unicodedata.category('八'))
print(unicodedata.category('8'))
print(unicodedata.category('{'))
输出结果如下:
Lu
上面结果分别表示大写字母、小写字母、其它字符、十进制数字和开始标点符号。
Ll
Lo
Nd
Ps
(3)unicodedata.combining(chr)
该函数以整数形式返回分配给字符的规范组合类,若未定义组合类,则返回0.
每个Unicode字符或编码点都会给分配一个规范组合类。它本质上指示组合字符附加到基本字符的优先级。规范组合类为0的字符是基本字符,值大于0的字符是组合字符。组合字符一般呈现在基本字符的附近,或附加到基本字符上,或环绕在基本字符周围。如一些字符是由基本字符加上标或下标构成的。这些上标或下标的形式、位置就是规范组合类的一种。
字符规范组合类的取值如下表所示。
Value |
Description |
---|---|
0: | Spacing, split, enclosing, reordrant, and Tibetan subjoined |
1: | Overlays and interior |
7: | Nuktas |
8: | Hiragana/Katakana voicing marks |
9: | Viramas |
10: | Start of fixed position classes |
199: | End of fixed position classes |
200: | Below left attached |
202: | Below attached |
204: | Below right attached |
208: | Left attached (reordrant around single base character) |
210: | Right attached |
212: | Above left attached |
214: | Above attached |
216: | Above right attached |
218: | Below left |
220: | Below |
222: | Below right |
224: | Left (reordrant around single base character) |
226: | Right |
228: | Above left |
230: | Above |
232: | Above right |
233: | Double below |
234: | Double above |
240: | Below (iota subscript) |
当然上面的规范组合类下并不是都有实例,只是以便今后扩展使用。
函数unicodedata.combining()的作用就是返回某个字符所属的规范组合类的值。
下面是一些例子:
import unicodedata
print(unicodedata.combining('A'))
print(unicodedata.combining('爱'))
print(unicodedata.combining(u'/u0301'))
print(unicodedata.combining(u'/u0345'))
print(unicodedata.combining(u'/u00D2'))
print(unicodedata.combining(u'/u1dE5'))
print(unicodedata.combining(u'/u0360'))
print(unicodedata.combining(u'/u1DF8'))
print(unicodedata.combining(u'/u0308'))
输出结果如下:
0
0
230
240
0
230
234
228
230
(4)unicodedata.decimal(chr[, default])
该函数的作用是返回数字字符(包括全角和半角)chr的十进制值,如果没有定义值,则返回指定的default值,否则会引发ValueError错误。
print(unicodedata.decimal('9'))
print(unicodedata.decimal('/u0031'))
print(unicodedata.decimal('/u0041'))
输出结果如下:
9
1
Traceback (most recent call last):
File "D:/01Lesson/PY/encode01.py", line 33, in <module>
print(unicodedata.decimal('/u0041'))
ValueError: not a decimal
总结了一下这个函数的作用:
在Unicode数据库中定义的字符,使用isdecimal()函数判断为True时,该字符作为参数传递给该函数时,可以输出对应的十进制数。
(5)unicodedata.digit(chr[ , default])函数
该函数返回数字字符的对应的阿拉伯数字形式。如果未定义这样的值,则返回default指定的值,否则将引发ValueError错误。
print(unicodedata.digit('1')) #全角数字字符
print(unicodedata.digit('⑨')) #带圈的数字字符
print(unicodedata.digit('¹')) #上角标数字字符
print(unicodedata.digit('⑶')) # 带括弧的数字字符
print(unicodedata.digit('⒈')) #带点的数字字符
输出结果:
1
9
1
3
1
该函数的参数chr在使用isdigit()函数验证为True时,能够正确输出对应的数字,否则会产生ValueError错误。
(6)unicodedata.lookup(name)
该函数的作用是按照给定的名字查询字符,并返回对应的字符,否则会引发ValueError错误。
import unicodedata
print (unicodedata.lookup('LEFT CURLY BRACKET'))
print (unicodedata.lookup('RIGHT SQUARE BRACKET'))
print (unicodedata.lookup('ASTERISK'))
print (unicodedata.lookup('EXCLAMATION MARK'))
print(unicodedata.lookup('TAMIL SYLLABLE TTAA'))
输出结果如下:
{
(7)unicodedata.mirrored(chr)
]
*
!
டா
该函数的作用是以整数形式返回字符chr是否支持镜像属性,如果该字符在双向文本中被识别为“镜像”字符,则返回1,否则返回0。
镜像在双向文本中非常重要,如括号"("在从左到右的文本中作为开始标记的左括号,但在从右到左的文本中应为其镜像字符:")"。类似这样的字符则是支持镜像的字符,再如“{”和“}”等。
print(unicodedata.mirrored('('))
print(unicodedata.mirrored('}'))
print(unicodedata.mirrored('"'))
输出结果如下所示:
1
1
0
(8) unicodedata.name(chr[, default])
该函数返回指定字符的名称,如未定义名称,则返回参数default的值,否则会引发ValueError错误。
print (unicodedata.name('%'))
print (unicodedata.name('|'))
print (unicodedata.name('A'))
print (unicodedata.name('a'))
print (unicodedata.name('9'))
print (unicodedata.name('*'))
print (unicodedata.name('@'))
print (unicodedata.name('爱'))
输出结果如下:
PERCENT SIGN
VERTICAL LINE
LATIN CAPITAL LETTER A
LATIN SMALL LETTER A
DIGIT NINE
ASTERISK
COMMERCIAL AT
CJK UNIFIED IDEOGRAPH-7231
(9)unicodedata.numeric(chr[, default])
该函数返回指定chr对应的数字形式,如果未定义这样的数字,将返回指定的default的值,否则将触发ValueError错误。
print(unicodedata.numeric('1')) #阿拉伯数字字符
print(unicodedata.numeric('一')) #汉字数字字符
print(unicodedata.numeric('①')) #带圈的数字字符
print(unicodedata.numeric('叁')) #大写汉字字符
print(unicodedata.numeric('㈠')) #带括弧的汉字字符
print(unicodedata.numeric('Ⅲ')) #罗马数字
输出结果如下:
1.0
1.0
1.0
3.0
1.0
3.0
实际上该函数的参数chr也是在使用isnumeric()函数验证该字符为True时才能输出对应的数字格式。
在使用上面介绍的decimal,digit,numeric三个函数时,首先要保证要作为参数的字符必须是单个字符,其次,作为参数的字符应该分别是十进制数位字符,某种编号的序位字符、用于表序或计量的数字字符。
以上介绍了Unicode编码的相关知识,并给出了Python中有关Unicode编码的几个函数,在内容写作过程中查阅了官方文档、众多网友的介绍,并结合自己的实验而写成,如有错误,请留言。
新闻热点
疑难解答