首页未分类 › Unicode、UTF-8、多字节字符、宽字符

Unicode、UTF-8、多字节字符、宽字符

Unicode、UTF-8
为了统一全世界各国语言文字的编码,ISO 制定
了ISO 10646 标准,也称为UCS(Universal Character Set)。UCS编码的长度是31位,可以表示2^31个字符。同时,另一组织制定了Unicode编码。后来ISO与这个组织联手统一了编码。所以Unicode与UCS是一样的。
有了字符编码,另一个问题就是这样的编码在计算机中怎么表示。现在最广泛用的是UTF-8,UTF是Unicode Transformation Format的缩写。UTF-8具有一下特点:

1.编码为U+0000~U+007F 的字符只占一个字节,就是0×00~0x7F ,和ASCII码兼容。

2.编码大于U+007F的字符用2~6 个字节表示(汉字用3字节表示),每个字节的最高位都是1 ,而ASCII码的最高位都是0 ,因此非ASCII码字符的表示中不会出现ASCII码字节(也就不会出现0 字节)。

3.用于表示非ASCII码字符的多字节序列中,第一个字节的取值范围是0xC0~0xFD,根据它可以判断后面有多少个字节也属于当前字符的编码。

具体来说,UTF-8 编码有以下几种格式:
U-00000000 – U-0000007F: 0xxxxxxx
U-00000080 – U-000007FF: 110xxxxx 10xxxxxx
U-00000800 – U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx
U-00010000 – U-001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
U-00200000 – U-03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
U-04000000 – U-7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
第一个字节要么最高位是0 (ASCII字节),要么最高两位都是1 ,最高位之后1 的个数决定后面有多少个字节也属于当前字符编码,例如111110xx,最高位之后还有四个1 ,表示后面有四个字节也属于当前字符的编码。
后面每个字节的最高两位都是10,可以和第一个字节区分开。
上面的格式中标为x的位就是UCS编码,最后一种6字节的格式中x位有31个,可以表示31位的UCS编码。

多字节字符、宽字符

一个汉字的存储通常占3 个字节。例如编辑一个C程序:

源文件是以UTF-8 编码存储的:
$ od -tc nihao.c
0000000 # i n c l u d e < s t d i o . 0000020 h > \n \n i n t m a i n ( v o i
0000040 d ) \n { \n \t p r i n t f ( ” 344 275
0000060 240 345 245 275 \ n ” ) ; \n \t r e t u r
0000100 n 0 ; \n } \n
0000107

其中八进制的344 375 240 (十六进制e4 bd a0 )就是“ 你” 的UTF-8 编码,八进制的345 245275 (十六进制e5 a5 bd )就是“ 好” 。

编译器把它编译成目标文件后,”你好\n” 这个字符串就成了这样一串字节:e4 bd a0 e5 a5 bd 0a 00(以0字节结尾),汉字在其中仍然是UTF-8 编码的,一个汉字占3 个字节,这种字符在C语言中称为多字节字符(Multibyte Character )。
所以用strlen求”你好\n”的长度,会得到结果7。这明显是不对的。

所以,我们应定义一个宽字符(wide char)串L”你好\n”,并用wstrlen求长度。
看下面程序:

L”你好\n”在源文件还是以UTF-8编码存储的:
$ od -tc nihao.c
0000400 } \n p r i n t
0000420 f ( ” % l s ” , L ” 344 275 240 345 245
0000440 275 \ n ” ) ; \n \n
0000460 r e t u r n 0
0000500 ; \n } \n
0000504

但编译器将其编译成目标文件时,L”你好\n”变成UCS编码了:
$:~/obj/java$ od -tx ~/obj/test/nihao.o |grep 4f60
0000340 00004f60 0000597d 0000000a 00000000

其中000004f60便是“你”的UCS编码(Unicode编码)。

还记得上面提到“你”的utf-8编码“e4 bd a0”吗?
e4 bd a0即为11100100 10111101 10100000,按“U-00000800 – U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx”格式从中取出0100、111101、100000,即得“你”的UCS编码00000000 00000000 01001111 01100000(16进制4f60)。

发表评论