第1节 理解字符
一、字体的设计原理(字符集、编码、字体三者的关系)
1、字符集:就是各种字符的集合,比如Unicode就是一个字符集,它使用2个字节(即最多65535个)来表示所有的字符。
2、编码:一个字符要能被计算机所接受,需要进行两次编码,因为计算机只能表示二进制,对于人们常使用的10进制来讲不是很方便,因此字符的第一次编码就是把相应的字符使用一个整数值与其相对应,比如ASCII码字符集把字符'a'编码为10进制的61,就是一次编码,Unicode字符集也是一次编码。为了能让计算机的二进制识别,需要把第一次编码后的整数值再次编码为二进制值,比如使用一个字节来表示字符'a'一次编码后的整数值61,再如中文汉字使用两个字节进行表示,再如对于Unicode字符集有3种不同的二次编码方案,分别是UTF-8,UTF-16和UTF-32,目前使用较多的是使用UTF-8来存储的Unicode字符集。
3、字形(glyph):用于表示字符的外形,比如字母a的ASCII码为61,但这个字母可以以多种外形对其进行书写,再如中文字符中的每一笔画都是一个字形。注:glyph也翻译为图元,图像。其实对象的外形都是使用图元进行描述的。
4、字形与字符的关系:一个字形可以用于表示多个字符,一个字符也可以由多个字形组成,比如中文字符,就经常共享字形,而且是由多个字形组成的。字符的衬线、粗细等都是字形设计的元素。
5、字体:是一个拥有相同设计风格的字形及从字符到字形映射关系的集合,字体使字符能被显示出来,字体是计算机显示文字的一种方式,比如早期电报就把字符表示为一长串数字,这一长串数字就相当于是字符集,当接收到电报后,是使用宋体、草书或者其他形式显示出来,就需要使用字体了,每种字体都有一个相应的名字,比如“Times New Roman”、“宋体”等,相同的字体显示的字符具有相似的风格,比如以宋体显示的字体,其风格都是相似的。另外,字体名通常有版权,是受到法律保护的。
6、计算机显示字符的原理简述:当计算机接收到一串二进制之后,表示的具体是什么字符,需要由字符集来决定,然后字符需要被显示出来(即字体以什么外观进行显示),这时就需要寻找相应的字体,若字库中没有相应字符的字体,则可能会被显示为乱码,所以要让计算机正确显示文字,不仅编码应正确,还要有相应的字体才行。
二、Unicode对字符的理解
1、用户感知字符(user-perceived character)与字形族 (grapheme cluster)
用户感知字符就是指的人们认为的一个字符,字形族是用于近似表示用户感知字符的。计算机中的一个“字符”通常就是一个Unicode代码值,但是,现实中人们认为的一个“字符”,可能并不是由一个Unicode代码值组成,而是由多个Unicode代码值组成的。比如
该字符会被人们认为是一个单个的字符,但实际上他是由两个Unicode代码值(即,两个字符)组成的,即由Unicode字符g (u+0067)和 (U+0308)组合而成。
2、字符的成形 (shaping)
在Unicode中,把字符以最终形状显示出来的过程称为成形。渲染引擎不一定能正确的对用户感知的字符成形,比如,有些渲染引擎可能会把显示为两个字符,有可能不会显示。
3、对字符的处理
由以上可知,用户感知字符与计算机理解的字符是不同的,而人们通常是以用户感知字符对字符进行理解的,因此,就有很多问题需要处理,比如,一个字符串中有多少个用户感知字符(即,怎样确定一个用户感知字符的边界),怎样对用户感知字符断行,怎样显示等,Unicode标准对这些方面都有详细的描述,有兴趣的读者可参阅Unicode有关这些方面的内容,本文重点介绍Unicode双向排序算法(bidi算法),bidi算法影响各个Unicode字符的排序顺序,至于字符能否最终成形为用户感知字符、怎样断行等内容不属于bidi算法的范围。
第2节 Unicode字符的分类与定向格式化字符
一、文本显示顺序与Unicode双向算法1、文本的方向大多数语言的文本在水平方向都是按从左到右(Left To Right,简称LTR)的顺序显示字符的,但也有不少语言是按从右到左(Right To Left,简称RTL)的顺序显示字符的(比如阿拉伯语、希伯来语)。当然还有按垂直方向书写的文本,比如中国古代的汉字就是从上到下从右到左书写的,本文只讨论水平方向书写的文本,垂直方向书写的文本不予讨论。双向文本是指一个字符串中同时包含LTR和RTL的文文,既包含从左到右的文本又包含从右到左的文本。现实中,从右向左书写的语言通常会夹杂着从左向右的文本(比如外语、引用、数字、符号等),因此,像阿拉伯语、希伯来语这些语言通常都是双向文本。另外,当在从左向右的文本中插入从右向左的文本时也会产生双向文本的问题。2、逻辑顺序与显示顺序逻辑顺序在Unicode标准内规定为文本在内存中表示的顺序,而显示顺序就是最终显示在我们面前所看到的文本的顺序,文本的逻辑顺序和显示顺序并不一定会一致,比如对于从右向左显示的文本,显示顺序应是从右向左的,而逻辑顺序则可能是从左向右的。逻辑顺序是属于计算机底层的问题,不属于本文讨论的范围,我们需要解决的是文本的显示顺序题。3、Unicode双向算法(bidi)与定向格式化字符1)、对于双向文本,若不明确的确定文本的显示顺序,在显示时就可能会出现歧义,为此,需要为双向文本的显示定义一种算法(或者一种规则),用于规范双向文本的显示顺序。2)、通常有一种隐式算法(或称为隐式双向排序或隐式布局算法)来定义双向文本的显示,但是隐式算法并不足以产生可供理解的文本,为此,对某些字符的显示顺序需要明确地进行控制,就是使用一系列的控制符(类似于HTML中的元素)来控制字符的显示顺序,这些控制符被Unicode称为定向格式化字符。比如,使用RLO控制符来控制字符从右向左显示,PDF表示RLO的终止字符,那么ab cd RLO EF GH PDF x,将被显示为ab cd HG FE x,可见,Unicode控制符的原理与HTML的元素是相似的。3)、定向格式化字符只影响文本的显示顺序,在其它方面会被忽略,也就是说定向格式化字符不会对文本的比较、断句、词法分析、数值分析等方面造成影响。4)、Unicode双向算法(也称为bidi)是对隐式算法的扩展, Unicode双向算法定义了定向格式化字符(即控制符),并且定义了一套算法,用于规定这些控制符对需要显示的字符产生怎样的影响。二、Unicode对字符的分类及输入方法1、字符的属性
Unicode为字符定义了很多属性,以用于描述该字符,比如Bidi_Paired_Bracket_Type属性用于描述该字符是开括号(值为open)还是闭括号(值为close),再如General_Category描述了该字符的通用类别,比如若该字符是行分隔符,则值为Line_Separator,是控制符,则值为Control等。
2、字符的类型
Unicode为每个Unicode字符都定义了一种类型(称为双向字符类型或bidi类型),双向字符类型被分为:强字符(强类型)、弱字符(弱类型)、中性字符(中性类型)、定向格式化字符,表1为具体的分类方法(定向格式化字符的分类见后文)
表1 字符的类型 |
|||
分类 |
类型 |
简述 |
范围 |
强字符(strong) |
L |
left to right |
LRM(见表2),大部分字母、音节、汉字、非欧洲或非阿拉伯数字 |
R |
right to left |
RLM(见表2),希伯来字母和相关的标点符号 |
|
AL |
right to left Arabic |
ALM(见表2),阿拉伯语(Arabic)、它拿字母(Thaana)、叙利亚字母,及大多数特定于这些文字的标点符号 |
|
弱字符(weak) |
EN |
欧洲数字(European Number) |
欧洲数字、东阿拉伯-印度数字,经常使用的数字1,2,3等就是属于EN类型 |
ES |
欧洲数字分隔符 |
加号,减号 |
|
ET |
欧洲数字终止符 |
度的符号,货币符号,比如,$(美元),¥(人民币)等 |
|
AN |
阿拉伯数字 |
阿拉伯-印度数字,阿拉伯小数和千位分隔符,平时使用的数字虽然叫做阿拉伯数字,但阿拉伯拥有自已的数字,比如,4的阿拉伯数字字符为 ٤ (u+0664) |
|
CS |
普通数字分隔符 |
冒号,逗号,句点(即小数点),不间断空格(no-break space)等,注意:单引号、双引号、分号不属于该类型,中文的句号也不属于该类型 |
|
NSM |
无间距标记(Nonspacing mark) |
属性General_Category为以下值的字符:Mn(Nonspacing_Mark)和Me(Enclosing_Mark)比如,组合用发音字符的上左角 ̚ (u+031A),西非书面文中的ࣾ (u+08FE) 。详见后文对组合字符的讲解 |
|
BN |
中性边界 |
不是明确给定类型的字符,比如:可忽略的默认值,非字符,控制字符等。比如,广义标点中的不可见乘号(u+2062)就是BN类型 |
|
中性字符(neutral) |
B |
段落分隔符 |
段落分隔符(u+2029),适当的换行符函数,高级别确定段落的协议 |
S |
节分隔符(Segment Separator) |
Tab |
|
WS |
空白(Whitespace) |
空格,图形空格,行分隔符,换页符,常用标点符号的空格等 |
|
ON |
其他中性符 |
所有其他字符,包括对象替换字符,比如,[、]、(、)、"、'、@、&、*、、<、>、|、{、}、;(分号)、!、?、~、=。注意:/ 属于CS类型、%、#属于ET类型 |
|
定向格式化字符 |
见后文 |