usf2 转成 utf8的转换函数

在网上找了个ucs2转utf8的C语言实现, 看他写的代码超级麻烦。虽然同样是实现了转换。

我这里提供一个比较经典的实现转换的函数,  用到的技术主要是位操作符号。该函数来自于

公司内部人员的一个模块。  写的非常棒, 就拿出来共享一下了。

 

在开始写之前还是附带上一些utf8与ucs2的资料, 方便理解该转换的宏模块

 

以下是从一些网站截取的一些基础资料

 =======================================================================

 

 1.什么是UCS和ISO10646?
国际标准ISO10646定义了通用字符集(Universal Character Set, UCS). UCS是所有其它字符集标准的一个超集,它保证也其它字符集双向兼容,即编码间相互转换不会丢失任何信息。UCS字符集U+0000到U+007F与US-ASCII是一致的

 

2.什么是UNICODE
历史上, 有两个独立的, 创立单一字符集的尝试. 一个是国际标准化组织(ISO)的 ISO 10646 项目, 另一个是由(一开始大多是美国的)多语言软件制造商组成的协会组织的 Unicode 项目. 幸运的是, 1991年前后, 两个项目的参与者都认识到, 世界不需要两个不同的单一字符集. 它们合并双方的工作成果, 并为创立一个单一编码表而协同工作. 两个项目仍都存在并独立地公布各自的标准, 但 Unicode 协会和 ISO/IEC JTC1/SC2 都同意保持 Unicode 和 ISO 10646 标准的码表兼容, 并紧密地共同调整任何未来的扩展.

 

3.什么是UTF-8(一种传送和存储格式)
UCS和UNICODE为每个字符分配了一个对应的整数,但并没有明确说明其实现机制.故存在多种编码方式,其中以两个字节和四个字节来存储一个字符的方法分别叫UCS-2, UCS-4,要将一个ASCII文件转换成一个UCS-2文件只要在每个字节前加一个字节0X00,转换成UCS-4只要在每个字节前加三个0X00。
而internet上大量的信息是以ASCII码存在的,如果都用两个字节来存储将浪费大量的资源,同时Unix和Linux下使用USC-2和USC-4会导致严重问题,于是出现了UTF-8(定义于ISO10646-1).
UTF-8(UTF-8 stands for Unicode Transformation Format-8. It is an octet (8-bit) lossless encoding of Unicode characters.)

 

UTF-8就是以8位为单元对UCS进行编码。从UCS-2到UTF-8的编码方式如下:

 

UCS-2编码(16进制)UTF-8 字节流(二进制)
0000 - 007F0xxxxxxx
0080 - 07FF110xxxxx 10xxxxxx
0800 - FFFF1110xxxx 10xxxxxx 10xxxxxx

例如“汉”字的Unicode编码是6C49。6C49在0800-FFFF之间,所以肯定要用3字节模板了:1110xxxx 10xxxxxx 10xxxxxx。将6C49写成二进制是:0110 110001 001001, 用这个比特流依次代替模板中的x,得到:11100110 10110001 10001001,即E6 B1 89。

读者可以用记事本测试一下我们的编码是否正确。需要注意,UltraEdit在打开utf-8编码的文本文件时会自动转换为UTF-16,可能产生混淆。你可以在设置中关掉这个选项。更好的工具是Hex Workshop。

UTF-16以16位为单元对UCS进行编码。对于小于0x10000的UCS码,UTF-16编码就等于UCS码对应的16位无符号整数。对于不小于0x10000的UCS码,定义了一个算法。不过由于实际使用的UCS2,或者UCS4的BMP必然小于0x10000,所以就目前而言,可以认为UTF-16和UCS-2基本相同。但UCS-2只是一个编码方案,UTF-16却要用于实际的传输,所以就不得不考虑字节序的问题。

 

========================================================================

 

下面是一个转换的宏模块:

 

//ucs2 char to utf8 char
#define UCS2_CHAR_CONVERT(c,dest,len) {\
	if(c < 0x80)\
		len = 1;\
	else if(c < 0x800)\
		len = 2;\
	else\
		len = 3;\
	switch (len) {\
		case 3: dest[2] = 0x80 | (c & 0x3f); c = (c >> 6) | 0x800;\
		case 2: dest[1] = 0x80 | (c & 0x3f); c = (c >> 6) | 0xc0;\
		case 1: dest[0] = (BYTE)c;\
	};\
}

 

代码的分析:

参数的含义:

@c: ucs2的一个字符, 2个字节

@dest: 存放转换后的一个数组, byte类型的, 数组长度是3

@len: 一个Int类型的技术flag, 用于记录ucs2的字符"c"转换成uft8需要多少个字节

 

代码段的第一个模块是, 判断字符"c"转换成uft8的存储格式需要几个字节。

 

代码段的第二个模块, 也就是switch语句: 作用是转换字符码。下面分析若len等于3的情况。

case3的步骤: 1、将"c"中的前6个字符取出来, 然后在加上1000 0000, 最终保存在数组3中的数据时10xxxxxx。

                       2、把"c"向右移动6位, 同时加上一个标志符号。     "c"结果为: 000010xx xxxxxxxx

 

case2的步骤: 1、将"c"中的后6个字符取出来, 加上1000 0000, 保存在数组2中的数据是10xxxxxx。

                       2、将"c"向右移动6位, 同时加上一个标志位。 "c"的结果为: 00000000 1110xxxx。

 

case1的步骤: 1、将"c"的剩余4位直接保存在数组1中。

这样就完成了3字节数据格式的转换了

 

至于2字节的转换, 1字节的转换, 我想聪明的你们一定应该知道是怎么回事了,以及如何使用它了。

希望这个函数能减轻你的代码量。

 

这是本人第一次对外写技术文档, 希望大家给点支持,同时给点意见, 以后我会继续将我工作中好的

代码拿出来给大家分享。

 

同时给大家点意见, 就是多看开源社区大师级的代码, 这样对你的代码质量会有很大的帮助。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值