UTF-8, Unicode, GB2312格式串转换之C语言版

  UTF-8, Unicode, GB2312格式串转换之C语言版 编程资料 2009-02-24 18:01 阅读83 评论0 字号: 大大 中中 小小 一、UTF8 -> Unicode 由于UTF8和Unicode存在着联系,所以不需要任何库就可以直接进行转换。首先要看懂UTF8的编码格式: 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 前面几个1就代表后面几个字节是属于一起的。如果要解析一长串UTF8格式的字符串,这点就很有用了。下面这个函数就是判断前面几个1的(这里有define APP_PRINT printf,这样当release的时候将这个宏定义为空就行了,不需要一个一个去改,又方便重新调试): int GetUtf8ByteNumForWord(u8 firstCh) { u8 temp = 0x80; int num = 0; while (temp & firstCh) { num++; temp = (temp >> 1); } APP_PRINT("the num is: %d", num); return num; } 利用这个函数可以得到字符串中那几个字节是一起的。因为UTF8最大只有6个字节,所以就根据返回值来处理这里我只处理了3个字节和1个字节的UTF8的编码,因为一般来说中文在UTF8中是3个字节。 //将len个字节的UTF8格式的转换成GB2312格式存放在temp预先申请好的缓冲区中 void Utf8ToGb2312(const char* utf8, int len, char *temp) { APP_PRINT("utf8->unicode: /n"); APP_PRINT("utf8: ["); for (int k = 0; k < len; k++) { APP_PRINT("%02x ", utf8[k]); } APP_PRINT("]/n"); int byteCount = 0; int i = 0; int j = 0; u16 unicodeKey = 0; u16 gbKey = 0; //循环解析 while (i < len) { switch(GetUtf8ByteNumForWord((u8)utf8[i])) { case 0: temp[j] = utf8[i]; byteCount = 1; break; case 2: temp[j] = utf8[i]; temp[j + 1] = utf8[i + 1]; byteCount = 2; break; case 3: //这里就开始进行UTF8->Unicode temp[j + 1] = ((utf8[i] & 0x0F) << 4) | ((utf8[i + 1] >> 2) & 0x0F); temp[j] = ((utf8[i + 1] & 0x03) << 6) + (utf8[i + 2] & 0x3F); //取得Unicode的值 memcpy(&unicodeKey, (temp + j), 2); APP_PRINT("unicode key is: 0x%04X/n", unicodeKey); //根据这个值查表取得对应的GB2312的值 gbKey = SearchCodeTable(unicodeKey); APP_PRINT("gb2312 key is: 0x%04X/n", gbKey); if (gbKey != 0) { //here change the byte //不为0表示搜索到,将高低两个字节调换调成我要的形式 gbKey = (gbKey >> 8) | (gbKey << 8); APP_PRINT("after changing, gb2312 key is: 0x%04X/n", gbKey); memcpy((temp + j), &gbKey, 2); } byteCount = 3; break; case 4: byteCount = 4; break; case 5: byteCount = 5; break; case 6: byteCount = 6; break; default: APP_PRINT("the len is more than 6/n"); break; } i += byteCount; if (byteCount == 1) { j++; } else { j += 2; } } APP_PRINT("utf8: ["); for (k = 0; k < j; k++) { APP_PRINT("%02x ", temp[k]); } APP_PRINT("]/n"); } 二、下面主要谈谈利用查表法来进行Unicode->GB2312的转换,首先下载码表,一般码表都是将GB2312的放在前面,Unicode放在后面,这样对于我们来说不方便使用,所以我转换了下,将Unicode放在前面,而且按照从小到大排好序。(这里只需要考虑都为两个字节的情况,因为前面的 UTF8->Unicode并没有将单字节的ASCII转换成Unicode) (1)做表:(可以到这里下载:http://blog.91bs.com/?action=show&id=20,这里谢谢渣渣的猪窝) 这个是原来的样子: 0x8140 0x4E02 #CJK UNIFIED IDEOGRAPH 0x8141 0x4E04 #CJK UNIFIED IDEOGRAPH 0x8142 0x4E05 #CJK UNIFIED IDEOGRAPH 先弄成(这个可以写个小程序来做,我就是在VC上做的,如果需要可以联系我): { 0x4E02 ,0x8140 }, //CJK UNIFIED IDEOGRAPH { 0x4E04 ,0x8141 }, //CJK UNIFIED IDEOGRAPH { 0x4E05 ,0x8142 }, //CJK UNIFIED IDEOGRAPH 这样就可以把这些放在.h文件中了,下面是我的定义: typedef struct unicode_gb { unsigned short unicode; unsigned short gb; } UNICODE_GB; UNICODE_GB code_table[] = { { 0x4E02, 0x8140 }, //CJK UNIFIED IDEOGRAPH { 0x4E04, 0x8141 }, //CJK UNIFIED IDEOGRAPH { 0x4E05, 0x8142 }, //CJK UNIFIED IDEOGRAPH 。。。。。。省略 下面这一步也很简单,在VC中用冒泡排序法对整个表进行排序,这里是按照unicode值进行排序,把排序后的最终结果打印出来,在cmd下运行name > 1.txt就输出到文件,这样就有了一个按照unicode排好序的unicode->gb2312码表。以下是源代码: int main(int argc, char *argv[]) { int num = 0; UNICODE_GB temp; int i = 0; int j = 0; num = sizeof(code_table) / sizeof(UNICODE_GB); printf("struct size: %d | total size: %d | num is: %d /n", sizeof(UNICODE_GB), sizeof(code_table), num); for (i = 0; i < num; i++) { for (j = 1; j < num - i; j++) { if (code_table[j - 1].unicode > code_table[j].unicode) { temp.unicode = code_table[j - 1].unicode; temp.gb = code_table[j - 1].gb; code_table[j - 1].unicode = code_table[j].unicode; code_table[j - 1].gb = code_table[j].gb; code_table[j].unicode = temp.unicode; code_table[j].gb = temp.gb; } } } printf("here is the code table sorted by unicode/n/n"); for (i = 0; i < num; i++) { printf("{/t0x%04X,/t0x%04X/t},/t/n", code_table[i].unicode, code_table[i].gb); } printf("/n/n print over!/n"); //以下注释掉的其实就是我用来对原来的码表添加,{,}等用的 /* char buff[100]; char buff_1[100]; FILE* fp = NULL; FILE *fp_1 = NULL; memset(buff, 0, 100); memset(buff_1, 0, 100); fp = fopen("table.txt", "rw"); fp_1 = fopen("table_1.txt", "a+"); if ((fp == NULL) || (fp_1 == NULL)) { printf("open file error!/n"); return 1; } while (fgets(buff, 100, fp) != NULL) { buff[8] = ','; fputs(buff, fp_1); } */ return 0; } 最后就是搜索算法了,前面已经排好序了,现在我们把排好序的码表放在我们真正需要的.h文件中。大家应该猜我用什么算法搜索了吧,二分法。 #define CODE_TABLE_SIZE 21791 //这个表是死的,所以就直接用宏表示长度,不用每次都用size,不过这样可能对移植性不好。 u16 SearchCodeTable(u16 unicodeKey) { int first = 0; int end = CODE_TABLE_SIZE - 1; int mid = 0; while (first <= end) { mid = (first + end) / 2; if (code_table[mid].unicode == unicodeKey) { return code_table[mid].gb; } else if (code_table[mid].unicode > unicodeKey) { end = mid - 1; } else { first = mid + 1; } } return 0; } 到此,已经能够将UTF8串转换成GB2312了。是一长串哦,而不是单个汉字的编码转换。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值