全球化,多语言,Unicode,UTF8
问题
在做游戏的全球化时,遇到的一个问题。
玩家名称可以混杂多国语言,但是要进行宽度检测。不同国家的字符宽度不同,比如中文、韩文、日文算2个宽度,其他算1个宽度。根据输入的多语言文本,准确计算宽度。
例如:
1 | 你好 - 4 |
这里泰文比较特殊一些,สวัสดี 在存储时会转为 สว◌ัสด◌ี,unicode中没有 วั 与 ดี 。
基础概念
字符集
字符集即字符的集合。
字符是各种文字和符号的总称,包含各国文字、标点符号、图形符号、数字等。
常见的字符集
字符集名称 | 别称 | 特点 | 技术特征 |
---|---|---|---|
ASCII | American Standard Code for Information Interchange, 美国信息互换标准编码 | 主要用于显示现代英语和其他西欧语言,是最通用的单字节编码系统 | 7bits表示一个字符,共128个字符(0-127),其中32-126是可打印字符 |
Unicode | Universal Multiple-Octet Coded Character Set, 通用多八位编码字符集 | 支持现今世界各种不同语言的书面文本的交换、处理、显示;对每种语言中的每一个字符都设定了统一且唯一的二进制编码 | 使用十六进制数字,在书写时前面加上前缀 “U+” |
UTF-8 | 8-bit Unicode Transformation Format, 将Unicode转成8bit格式 / 万国码 | 便于不同的计算机之间使用网络传输不同语言和编码文字,使得双字节的Unicode能在现存处理单字节系统上正确传输 | UTF-8是一种针对Unicode的可变长字符编码;用1-6个字节编码Unicode字符,对应还有 UTF-16 与 UTF-32 |
GB2312 | 信息交换用汉字编码字符集·基本集 | 中国国家标准的简体中文字符集,于1981.5.1日实施 | 1. 区位码(分区表示);对所收录的汉字进行分区处理,每区含有94个汉字/符号。 2. 双字节表示,即两个字节来编码一个字,高位字节与低位字节有各自范围 |
GB18030 | 信息交换用汉字编码字符集基本集的扩充 | 中国政府于2000年3月17日发布的汉字编码国家标准,2001年8月31日后在中国市场上发布的软件必须符合本标准;解决了汉字、日文假名、朝鲜语和中国少数民族文字组成的大字符集计算机编码问题。与 Unicode 3.0兼容,并且与 GB2312兼容 | 采用 单字节、双字节、四字节三种方式对字符编码。单字节部分使用 0x00-0x7F(与ASCII码对应) |
BIG5 | 大五码/五大码 | 收录13053个中文字,在中国台湾使用广泛 | 双字节表示,即两个字节来编码一个字,高位字节与低位字节有各自范围 |
字符编码
为什么需要编码?
- 为了便于存储与传输,需要一个统一的规则来存取信息。(某段二进制代表什么信息)
如何进行字符编码?
- 编码转码所需元素:
- 字库表,所有可读/可写的字符数据库
- 编码字符集,表示一个字符在字库表中的位置
- 字符编码,编码字符集与字库表的映射关系
- 过程
- 编码
- 拿到一个字符准备存储
- 通过字符编码得到在编码字符集中值
- 将得到值存储
- 转码
- 得到要显示的值
- 通过字符编码得到对应字库中的值
- 将得到值进行显示
- 编码
- 通过字符编码可以节省字库表大小
Unicode & UTF-8
UTF-8编码为变长编码,最小编码单位(code unit)为一个字节,每个字节的前1-3个bit为描述性部分,后面的为实际序号部分。
- 字节以 0 开头,当前字符为单字节字符,占用一个字节的空间;0之后的所有部分代表在Unicode中的序号。
- 字节以 10 开头,当前字符为多字节字符,当前字节为多字节字符的第二字节,10 后所有部分和第一字节的剩余部分共同组成在Unicode中的序号。
- 字节以 110 开头,当前字符为双字节字符,当前字节为双字节字符的第一字节,110 后所有部分与第二字节剩余部分共同组成在Unicode中的序号。(第二字节以10开头)
- 字节以 1110 开头,当前字符为三字节字符,当前字节为三字节字符的第一字节,1110 后所有部分与第二字节剩余部分第三字节剩余部分共同组成在Unicode中的序号。(第二字节与第三字节均以10开头)
计划
字节 | 标准格式 | 容纳位数 | 16进制范围 |
---|---|---|---|
单字节 | 0xxx xxxx | 0-7 | 0x0000 - 0x007F |
双字节 | 110x xxxx 10xx xxxx | 8-11 | 0x0080 - 0x07FF |
三字节 | 1110 xxxx 10xx xxxx 10xx xxxx | 12-16 | 0x0800 - 0xFFFF |
实际应用
实际字符 | 在Unicode字库中十六进制 | 在Unicode字库中二进制 | UTF-8编码后的二进制 | UTF-8编码后十六进制 |
---|---|---|---|---|
H | 0048 | 100 1000 | 0100 1000 | 48 |
Ĉ | 0108 | 1 0000 1000 | 1100 0100 1000 1000 | C4 88 |
你 | 4F60 | 100 1111 0110 0000 | 1110 0100 1011 1101 1010 0000 | E4 BD A0 |
Lua & Unicode
Lua是否支持Unicode的呢?
在官网FAQ中,有一些讨论: Can I use unicode strings? or Does Lua support unicode?
主要意思就是Lua并不知道存储/处理的是否为Unicode,但Lua字符串是一个任意序列的字节序列,可以存储任意二进制的数据,包括Unicode;然后根据处理需求可自行扩展相应逻辑。
处理UTF-8的第三方文件:
方案
按照需求,可定流程
- 求出字符串的unicode值
- 查找unicode值区间,判断所属国家
- 根据国家来进行不同长度计算
PS: 整个utf8相关方法,在文章最下方
1 | -- http://www.unicode.org/charts/nameslist/ |
参考文章: