Unicode 是一种在计算机上使用的字符编码,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。注意,Unicode 仅仅是定义了一个字符映射表,而没有实现具体的编码。例如:大写字符 ‘A' 的 Unicode 码是 0x41,汉字 “中” 的 Unicode 码是 0x4E2D,这仅仅是一种简单的对应关系,至于如何存储这些 Unicode 码,就是具体编码规则定义的。你可以用 2 个字节来表示 ‘A’ 和 “中” 的 Unicode 码,甚至可以用 3 个字节或 4 个字节,但是不同的编码规则对资源的利用和读写的效率是不一样的。
对于简体汉字的 Unicode 码,其值是位于 0x4E00 - 0x9FCF 这个范围,具体可以参考 。
UTF-8(Universal Transformation Format 通用转换格式)是 Unicode 的一种变长字符编码,又称万国码,由 Ken Thompson 于 1992 年创建。现在已经标准化为 RFC 3629。UTF-8 用 1 到 6 个字节编码 Unicode 字符。用在网页上可以同一页面显示中文简体繁体及其它语言(如日文,韩文)。
UTF-8 编码字节含义:
对于 UTF-8 编码中的任意字节 B,如果 B 的第一位为 0,则 B 为 ASCII 码,并且 B 独立的表示一个字符;
如果 B 的第一位为 1,第二位为 0,则 B 为一个非 ASCII 字符(该字符由多个字节表示)中的一个字节,并且不为字符的第一个字节编码;
如果 B 的前两位为 1,第三位为 0,则 B 为一个非 ASCII 字符(该字符由多个字节表示)中的第一个字节,并且该字符由两个字节表示;
如果 B 的前三位为 1,第四位为 0,则 B 为一个非 ASCII 字符(该字符由多个字节表示)中的第一个字节,并且该字符由三个字节表示;
如果 B 的前四位为 1,第五位为 0,则 B 为一个非 ASCII 字符(该字符由多个字节表示)中的第一个字节,并且该字符由四个字节表示;
因此,对 UTF-8 编码中的任意字节,根据第一位,可判断是否为 ASCII 字符;根据前二位,可判断该字节是否为一个字符编码的第一个字节; 根据前四位(如果前两位均为1),可确定该字节为字符编码的第一个字节,并且可判断对应的字符由几个字节表示;根据前五位(如果前四位为1),可判断编码是否有错误或数据传输过程中是否有错误。
例如:汉字“中”的 Unicode 码为 0x4E2D,在 UTF-8 中表示为 0xE4 0xB8 0xAD。
E4 B8 AD /* UTF-8 */
1110 0100 1011 1000 1010 1101
0100 11 1000 10 1101
0100 1110 0010 1101
4E 2D /* UNICODE */
数码相框中
每一个字符编码器对应一个 struct encode 结构体对象:
struct encode {
char *name;
int head_size;
int (*support)(unsigned char *raw);
int (*get_code)(unsigned char *head, unsigned char *tail, unsigned int *code);
struct list_head list;
};
对于 UTF-8 格式的文本,在文件最开始三个字节处存放的是 EF BB BF。成员 head_size 记录了文件头的大小,对于 UTF-8 格式的文件,其值应为 3。
1.核心层 encode_core.c 简要分析:
static struct list_head encode_list;
/* 必须第一个被调用,用来初始化链表头 */
void encode_core_init(void)
{
INIT_LIST_HEAD(&encode_list);
}
void register_encode(struct encode *encode)
{
list_add(&encode->list, &encode_list);
}
struct encode * select_encode(unsigned char *raw)
{
struct encode *encode;
struct list_head *pos;
list_for_each(pos, &encode_list)
{
encode = list_entry(pos, struct encode, list);
if(encode->support(raw))
return encode;
}
return NULL;
}
核心层主要提供一些接口供外部函数调用,在使用字符编码器时,必须要先调用 encode_core_init() 函数,它是用来初始化一个链表头,所有系统注册过的字符编码器都会被加入该链表。同样,当读取文本文件的原始数据后,应该使用 select_encode() 函数来选择相应的能处理该文本的字符编码器。
2.UTF-8 字符编码器 utf-8.c 简要分析:
struct encode utf8_encode = {
.name = "utf-8",
.head_size = 3, //头部含有3个字节
.support = utf8_support,
.get_code = utf8_get_unicode,
};
/* 判断该文本是否是 UTF-8 编码格式 */
static int utf8_support(unsigned char *raw)
{
const char head[] = {0xEF, 0xBB, 0xBF, 0};
if(strncmp(head, (const char*)raw, 3) == 0)
return 1;
else
return 0;
}
/* 分析某一字符包含的字节数 */
static int analyze_code_info(unsigned char byte)
{
int i;
int count = 0;
for(i=7; i>=0; i--)
{
if((byte & (1< break;
else
count++;
}
return count;
}
/* 获得某一个字符的 Unicode 码 */
static int utf8_get_unicode(unsigned char *head, unsigned char *tail, unsigned int *code)
{
int num;
unsigned char val;
unsigned int sum = 0;
int i;
if(head >= tail) /* 文件结束 */
return 0;
num = analyze_code_info(head[0]);
if ((head + num) > tail) /* 文件结束 */
return 0;
if (num == 0) /* ASCII */
{
*code = head[0];
return 1;
}
else
{
val = head[0] << num;
val = val >> num;
sum += val;
for (i = 1; i < num; i++)
{
val = head[i] & 0x3f;
sum = sum << 6;
sum += val;
}
*code = sum;
return num;
}
}
/* 向系统注册 UTF-8 字符编码器 */
void utf8_encode_register(void)
{
register_encode(&utf8_encode);
}
int utf8_get_unicode(unsigned char *head, unsigned char *tail, unsigned int *code);
utf8_get_unicode() 函数用于获得某一个字符的 Unicode 码,该字符在文件中的存放位置是 head,文件的结束位置是 tail,获得的 Unicode 码存放在参数 code 中,函数返回此编码格式下表示该字符所使用的字节数。
——忠于梦想 勇于实践 linux_xpj@opencores.org
阅读(2116) | 评论(0) | 转发(0) |