引言
中日韩越統一表意文字(CJKV Unified Ideographs),也称統一汉字(Unihan),目的是要把分別来自中文、日文、韩文、越文、壮文中,对於相同起源、本义相同、形状一样或稍异的表意文字,应赋予其在 ISO 10646 及統一码(Unicode)标准中有相同编码。
截至目前 (2012年,Unicode 6.2) 为止,中日韩越统一表意文字共有 75,617 字,来源于以下几个方面:
- 统一汉字基本集,共 20,941 字,其范围为:U+4E00 - U+9FCC。
- 上面的统一汉字基本集中 U+4E00 - U+9FA5 的 20,902 个汉字(GB13000:GBK),是在1993年引进的(Unicode 1.0)。
- 上面的 GBK 汉字包括 GB2312 的 6,763 个汉字。
- 上面的统一汉字基本集中的 U+9FA6 - U+9FBB 范围的 22 个汉字是在2005年引进的(Unicode 4.1)。
- 上面的统一汉字基本集中的 U+9FBC - U+9FC3 范围的 8 个汉字是在2008年4月引进的(Unicode 5.1)。
- 上面的统一汉字基本集中的 U+9FCC 这一个汉字是在2012年引进的(Unicode 6.1)。
- 扩展区(A),共 6,582 字,其范围为:U+3400 - U+4DB5。这是在1999年引进的。
- 扩展区(B),共 42,711 字,其范围为:U+20000 - U+2A6D6。这是在2001年引进的。
- 扩展区(C),共 4,149 字,其范围为:U+2A700 - U+2B734。这是在2009年10月引进的(Unicode 5.2)。
- 扩展区(D),共 222 字,其范围为:U+2B740 - U+2B81D。这是在2010年引进的(Unicode 6.0)。
- 兼容汉字(1),共 302 字,其范围为:U+F900 - U+FA2D。
- 兼容汉字(2),共 62 字,其范围为:U+FA30 - U+FA6D。
- 兼容汉字(3),共 106 字,其范围为:U+FA70 - U+FAD9。来自北朝鲜。
- 兼容汉字(4),共 542 字,其范围为:U+2F800 -U+2FA1D。来自台湾。
上述的统一汉字基本集是最重要的,特别是 20,902 个 GBK 汉字,大多数操作系统都可以正确处理这些汉字。其余汉字在有些操作系统中可能不能正确显示。
生成全部中日韩越统一表意文字
根据上面的讨论,我们就可以生成全部中日韩越统一表意文字了,相应的 C# 程序如下所示:
1 using System; 2 using System.Text; 3 4 // 生成全部中日韩越统一表意文字 5 sealed class UnihanCreator 6 { 7 static int [,] Groups = { // 75,617 合计 (Unicode 6.2) 8 { 0x4E00, 0x9FCC }, // 20,941 统一汉字基本集 9 { 0x3400, 0x4DB5 }, // 6,582 统一汉字扩展区(A) 10 { 0x20000, 0x2A6D6 }, // 42,711 统一汉字扩展区(B) 11 { 0x2A700, 0x2B734 }, // 4,149 统一汉字扩展区(C) 12 { 0x2B740, 0x2B81D }, // 222 统一汉字扩展区(D) 13 { 0xF900, 0xFA2D }, // 300 兼容汉字(1) 14 { 0xFA30, 0xFA6D }, // 62 兼容汉字(2) 15 { 0xFA70, 0xFAD9 }, // 106 兼容汉字(3) 16 { 0x2F800, 0x2FA1D }, // 542 兼容汉字(4) 17 }; 18 19 static void Main() 20 { 21 var sb = new StringBuilder(); 22 for (var i = 0; i < Groups.GetLength(0); i++) 23 for (var j = Groups[i, 0]; j <= Groups[i, 1]; j++) 24 sb.Append(GetUtf16Chars(j)); 25 Console.WriteLine(sb); 26 } 27 28 static char[] GetUtf16Chars(int n) 29 { 30 if (n <= char.MaxValue) return new char[]{ (char)n }; 31 return new char[]{ (char)(0xD800 | ((n - 0x10000) >> 10)), (char)(0xDC00 | (n & 0x3FF)) }; 32 } 33 }
在 Arch Linux 的 Mono 环境下编译和运行:
work$ dmcs UnihanCreator.cs work$ mono UnihanCreator.exe 一丁丂七丄丅丆万丈三上下丌不与丏丐丑丒专且丕世丗 ... 讛讜讝讞讟讠计订讣认讥 ... 䶯䶰䶱䶲䶳䶴䶵𠀀𠀁 ...
是不是有很多不认识的字?
测试程序
下面是一个测试程序 UnihanTester.cs:
1 using System; 2 using System.Text; 3 4 static class UnihanTester 5 { 6 static readonly Encoding GB18030 = Encoding.GetEncoding("GB18030"); 7 8 static void Main() 9 { 10 Console.WriteLine("-Code Chars---- Unicode---- GB18030---- UTF8------- [--]"); 11 foreach (var n in new int[]{ 0x3F, 0x25CB, 0x3400, 0x4DB5, 12 0x4E00, 0x9FA5, 0x9FA6, 0x9FCB, 0x9FCC, 0xF900, 0xFA2D, 0xFA30, 0xFA70, 13 0x20000, 0x2A6D6, 0x2A700, 0x2B734, 0x2B740, 0x2B81D, 0x2F800, 0x2FA1D }) 14 { 15 var s = new string(GetUtf16Chars(n)); 16 Console.WriteLine("{1,5:X} {2,-9} {3,-11} {4,-11} {5,-11} [{0}]", 17 s, n, GetCharsHexString(s), 18 BitConverter.ToString(Encoding.Unicode.GetBytes(s)), 19 BitConverter.ToString(GB18030.GetBytes(s)), 20 BitConverter.ToString(Encoding.UTF8.GetBytes(s))); 21 } 22 } 23 24 static string GetCharsHexString(string s) 25 { 26 var sb = new StringBuilder(); 27 foreach (var c in s) sb.AppendFormat("{0:X4}-", (int)c); 28 if (sb.Length > 0) sb.Length--; 29 return sb.ToString(); 30 } 31 32 static char[] GetUtf16Chars(int n) 33 { 34 if (n <= char.MaxValue) return new char[]{ (char)n }; 35 return new char[]{ (char)(0xD800 | ((n - 0x10000) >> 10)), (char)(0xDC00 | (n & 0x3FF)) }; 36 } 37 }
在 Arch Linux 的 Mono 环境下编译和运行:
运行结果还不错,大部分测试的汉字都能显示。U+10000 以上的字在 .NET Framework Class Library 的 Unicode (UTF-16) 编码中是使用两个 Char 分为高、低位代理表示的,也能正确显示为一个字符。
在 Windows 7 操作系统的 .NET Framework 4.5 下编译:
C:\work> csc UnihanTester.cs Microsoft(R) Visual C# 编译器版本 4.0.30319.17929 用于 Microsoft(R) .NET Framework 4.5 版权所有 (C) Microsoft Corporation。保留所有权利。
运行结果如下所示:
这下就有许多测试的汉字显示不出来了。而且 U+10000 以上的字作为两项显示了。
中日韩越统一表意文字的字形
这 75,617 字的字形可从 Unicode 网站的 Unicode 6.2 Character Code Charts 页面下载,具体如下:
work$ wget http://www.unicode.org/charts/PDF/U25A0.pdf work$ wget http://www.unicode.org/charts/PDF/U3400.pdf work$ wget http://www.unicode.org/charts/PDF/U4E00.pdf work$ wget http://www.unicode.org/charts/PDF/UF900.pdf work$ wget http://www.unicode.org/charts/PDF/U20000.pdf work$ wget http://www.unicode.org/charts/PDF/U2A700.pdf work$ wget http://www.unicode.org/charts/PDF/U2B740.pdf work$ wget http://www.unicode.org/charts/PDF/U2F800.pdf work$ ls -lh *.pdf -rw-r--r-- 1 ben users 39M 8月 28 02:59 U20000.pdf -rw-r--r-- 1 ben users 193K 8月 28 02:59 U25A0.pdf -rw-r--r-- 1 ben users 3.2M 8月 28 02:59 U2A700.pdf -rw-r--r-- 1 ben users 225K 8月 28 02:59 U2B740.pdf -rw-r--r-- 1 ben users 586K 8月 28 02:59 U2F800.pdf -rw-r--r-- 1 ben users 6.5M 8月 28 02:59 U3400.pdf -rw-r--r-- 1 ben users 34M 8月 28 02:59 U4E00.pdf -rw-r--r-- 1 ben users 682K 8月 28 02:59 UF900.pdf
看个例子:
上图中的 U+2F800 是兼容汉字(4)中的字,它等价于 U+4E3D,是统一汉字基本集中的“丽”字。前面的测试程序在 Linux 中运行时,很聪明地使用这个等价的“丽”字来显示 U+2F800。