全角字符

在等宽字体中占据半角字符两倍宽度的字符。中日韩文字通常为全角。

全角字符是指在等宽字体中占据半角字符两倍宽度的字符。中文汉字、日文假名,以及全角英文数字与符号都属于全角字符。这一概念起源于日语计算机处理的早期,用于区分 1 字节的 ASCII 字符 (半角) 和 2 字节的日语字符 (全角)。

在 Unicode 中,每个字符都定义了 East Asian Width 属性,分为 Fullwidth (F)、Wide (W)、Halfwidth (H)、Narrow (Na)、Ambiguous (A) 和 Neutral (N) 六类。日语汉字和假名属于 Wide (W),ASCII 字符属于 Narrow (Na)。被归类为 Ambiguous (A) 的字符 (如部分希腊字母和西里尔字母) 在不同环境下可能显示为全角或半角,这可能导致布局错乱。

在字符计数上,全角与半角的处理方式因平台而大不相同。X (Twitter) 采用给每个字符赋予权重的方式,汉字、假名、韩文等 CJK 字符 1 个字符按权重 2 计算,所以面对上限 280 的额度,日语实际上只放得进 140 个字符。SMS 的性质则不同,全角和半角都按 1 个字符计数,但只要混进 1 个日语字符,传输用的编码就会切换成 UCS-2,1 条短信的上限本身会从 160 个字符降到 70 个字符。Google 广告的标题上限是 30 个字符,而日语、中文、韩语的字符按 1 个字符 = 2 个字符份来计数,因此实际只有 15 个字符。像这样,能用「全角 = 半角 2 个字符」这一个换算式说明清楚的机制其实很少,要准确计数就得逐个掌握目标平台的规则。

在数据库设计中,需要注意全角字符的字节数因编码而异。UTF-8 中全角字符占 3 个字节,UTF-16 中占 2 个字节。不过这说的是收在基本多文种平面之内的字符,𠮟 这样的扩展汉字在 UTF-8 中占 4 个字节,在 UTF-16 中也要用代理对占掉 4 个字节。在 VARCHAR(255) 的列里用 UTF-8 只存全角字符时,按字节数限制的话最多只放得进 85 个字符;而按字符数限制 (MySQL 的情形) 则可以存到 255 个字符。不理解这一差异,就会招致数据被截断或者报错。

Web 表单的输入验证中,经常需要进行全角与半角之间的转换处理。电话号码和邮政编码的输入里用上全角数字的情况很多,用 JavaScript 的 String.prototype.normalize('NFKC') 就可以把全角英文数字正规化为半角。反过来,把片假名统一为全角的处理,在地址输入等场景中也会被要求。不过 NFKC 并不会只瞄准全角英文数字来转换。半角片假名会变成全角,带圈数字 ① 会变成 1,㍿ 会变成「株式会社」,全角空格会换成半角空格,这些都是一并被替换掉的。本想着做电话号码栏的正规化却套用到了正文整体,就会混进意料之外的改写,所以把适用范围按输入栏为单位收窄才安全。

使用字符计数工具时,意识到全角与半角的区别会如何影响计数结果很重要。在按「全角 1 个字符 = 半角 2 个字符」换算的系统中,同样的内容如果多用全角,字符数就会增加。在有字符数限制的场景中,可以通过把全角片假名转换成半角、把全角空格替换成半角空格等办法,设法收进限制之内。不过这只在限制以显示宽度或换算规则为依据的时候才有效。若是以 UTF-8 的字节数来限制的场面,把全角片假名改成半角片假名仍然是 1 个字符 3 个字节,并不会减少 (而把全角空格换成半角空格的替换,则会从 3 个字节减到 1 个字节)。字节数的限制与显示宽度的限制,必须当作两回事切分开来考虑。

分享这篇文章