UTF-8, Unicode, GB2312格式串转换之C语言版
原住址:http://www.cnitblog.com/wujian-IT/archive/2007/12/13/37671.html
/* author: wu.jian (吴剑) English name: Sword
/* date: 2007-12-13
/* purpose: 知识共享
这几天工作上碰到了UTF-8转GB2312的问题,而且是在嵌入式的环境下,没有API可用,查了很多网上的资料,大多调用VC或者Linux下自带的接口。在这里我将这两天的工作做个总结。
总的来说分为两大步(这里就不介绍基础知识了):
一、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) //判断前面几个1
{
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了。是一长串哦,而不是单个汉字的编码转换。
UTF-8, Unicode, GB2312格式串转换之C语言版的更多相关文章
- 7、UTF-8, Unicode, GB2312格式串转换之C语言版
(申明:此文章属于原创,若转载请表明作者和原处链接 ) /* author: wu.jian (吴剑) English name: Sword ...
- ASP:GB2312格式文本文件转换成UTF-8格式
'-------------------------------------------------'函数名称:gb2utf_file'作用:利用AdoDb.Stream对象来把GB2312格式文本文 ...
- UNICODE串转换成char类型串的四种方法
1. 调用 WideCharToMultiByte() API int WideCharToMultiByte ( UINT CodePage, //1 U ...
- 各种编码中汉字所占字节数;中文字符集编码Unicode ,gb2312 , cp936 ,GBK,GB18030
vim settings set fileencodings=utf-8,ucs-bom,gb18030,gbk,gb2312,cp936,latin1set termencoding=utf-8se ...
- 中文字符集编码Unicode ,gb2312 , cp936 ,GBK,GB18030
中文字符集编码Unicode ,gb2312 , cp936 ,GBK,GB18030 cp936是微软自己发布的用在文件系统中的编码方式.而bg2312是中国国家标准.我明白mount -t vfa ...
- 创建文件夹并解决解决unicode和ASCII码转换的问题
# -*- coding: UTF-8 -*-import sysimport timeimport os #解决unicode和ASCII码转换的问题reload(sys) #解决unicode和A ...
- Unicode编码解码在线转换工具
// Unicode编码解码在线转换工具 Unicode 是基于通用字符集(Universal Character Set)的标准来发展,并且同时也以书本的形式(The Unicode Standar ...
- [转] 将DOS格式文本文件转换成UNIX格式
点击此处阅读原文 用途说明 dos2unix命令用来将DOS格式的文本文件转换成UNIX格式的(DOS/MAC to UNIX text file format converter).DOS下的文本文 ...
- 将形如:Oct 8, 2016 5:29:44 PM串转换成正常时间在真机上遇到的坑
将形如:Oct 8, 2016 5:29:44 PM串转换成正常时间在真机上遇到的坑 /** * 根据传入字符串 * * @param str 传入的日期字符串 形如:Oct 8, 2016 5:29 ...
随机推荐
- php 当前时间计算操作
首先要设置时间为中国时区 date_default_timezone_set('PRC'); 对于获取当前时间戳后的各种时间计算 数据库保存最好用时间戳 当前时间time() 上一天 echo dat ...
- Codeforces Round #386 (Div. 2) C D E G
一场比较简单的题 比较脑洞 C 如果坐车比较快的话 先走不如等车 所以最后的ans是min(纯走路,纯坐车) 讨论一下坐车时间 D 因为k一定是>=1的 所以当a=b的时候 GBGBGB这样间隔 ...
- JavaScript -- 控制table的创建 与 删除, 排序, 表格颜色
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- 在物理机安装CentOS6.5
这两天就要开始在用户的新服务器上部署生产环境了.之前一直都是在服务器上搭虚拟机,而在物理机上安装还是第一次. 首先是要准备启动程序.我用的U盘作为启动盘. 刻盘的操作参考 http://jingyan ...
- git 里面遇到的问题
第一步:建立git仓库(本地) cd到你的本地项目根目录下,执行git命令 git init 第二步:将项目的所有文件添加到仓库中 git add . 如果想添加某个特定的文件,只需把.换成特定的文件 ...
- SQL Server 中WITH (NOLOCK)浅析(转)
概念介绍 开发人员喜欢在SQL脚本中使用WITH(NOLOCK), WITH(NOLOCK)其实是表提示(table_hint)中的一种.它等同于 READUNCOMMITTED . 具体的功能作用 ...
- Linux命令之awk_1
简介 awk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大.简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再 ...
- wpf多程序集之间共享资源字典--CLR名称空间未定义云云
wpf多程序集之间共享资源字典--CLR名称空间未定义云云 分类: WPF 2012-10-28 10:57 1162人阅读 评论(0) 收藏 举报 以下介绍如何创建可用于在多个程序集之间共享的资源字 ...
- FunnelWeb 开源Blog引擎介绍
FunnelWeb is an open source blog engine, built by developers for developers. Instead of fancy quotes ...
- 从AD域获取用户AD信息
public static Dictionary<string, string> SearchADInfo(string adName) { string strTemp = " ...