首页 > 开发 > Python > 正文

Python中的unicode编码格式

2023-04-25 12:32:04
字体:
来源:转载
供稿:网友

这篇文章将介绍Unicode编码的相关知识以及Python中Unicode编码的相关内容。

为了讲清楚这个问题,我们从计算机的字节及字符编码开始说起。

1 字节

字节(Byte)是计算机信息技术中用于计量存储容量的一种单位,通常情况下,一个字节等于8位(bit),1位可以表示为二进制中的0或1。

在很多计算机语言中,字节(Byte)也是一种数据类型,用于存储字符。

在不同的字符编码方式中,一个字符占用的字节数量可能不同。如在ASCII编码方式下,用一个字节来存储1个字符。

一个字节共8位,对应的无符号二进制数可以有256种(即28种)情形(0~255,最大数:28-1),如果用一个二进制数表示一个字符的话,那么最多可以表示256个不同字符。

2 字符编码

为了便于在计算机中进行存储和传递信息,在计算机技术中,将每个字符(包括控制字符,如回车、换行等)都分配唯一一个整型数字与其对应。如ASCII(American Standard Code for Information Interchange,美国信息交换标准码)使用8位二进制数对字符(包括字母、数字、标点符号、控制字符及其它符号)进行编码。因为八位的二进制数可以有256种数位(0和1)组合,最多能对256个字符进行编码,这种情况下对于处理英文信息是完全够用的,但是随着计算机在全世界的普及使用,这种编码方式已不足来处理更多的字符信息了,如我们常用的基本汉字就有三千多个,而ASCII编码方式最多能为256个字符编码,显然这种编码方式远远不够用的,因此,我国随后推出了汉字区位编码方式,GB2312,GBK以及为处理繁体字设计的Big5等。

不同的编码方式可能存在着冲突,即某一个编码在不同的编码方式中表示不同的字符,这为信息交换又带来了困难,因此后来人们设计了能够全球统一使用的Unicode编码方式。

Python中的Unicode编码

3 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是后来发展起来的编码方式。

4 UTF-8编码

UTF-8编码方式是目前使用最广泛的一种编码方式。UTF-8使用的是8位单字节码元编码方式,但并非所有的字符都采用1个码元来编码,其编码序列可能为1~4个字节或更长。如英文字符仍占1个字节,而汉字占用3个字节来存储。

在具体实现中,UTF-8首字节用于识别编码的字节数。其规则为:除单字节编码以0开头外,多字节编码首字节1的个数用于判断编码后的字节长度,然后紧接着以数字0作为终结标志,除首字节外,多字节编码的后续字节都以10开头。

UTF-8使用变长字节来编码能够节省空间,易于扩展,且与已有的ASCII兼容。

UTF-16和UTF-32采用固定长度的编码方式也能够对全球语言的字符或符号进行编码,但不管是西文还是像亚洲的中日韩都使用统一的长度来存储,相对来说比较浪费空间。

5 Python中的字符编码方式

再回到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个之多。而英文字母仍然原样输出。

6 Python中的unicodedata模块

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编码的几个函数,在内容写作过程中查阅了官方文档、众多网友的介绍,并结合自己的实验而写成,如有错误,请留言。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表