赞
踩
GBK:GBK全名为汉字内码扩展规范,英文名Chinese Internal Code Specification。GBK 采用双字节表示,总体编码范围为8140-FEFE,首字节在81-FE 之间,尾字节在40-FE 之间,剔除 xx7F一条线。总计23940 个码位,共收入21886个汉字和图形符号,其中汉字(包括部首和构件)21003 个,图形符号883 个。
UNICODE:unicode是一种支持全世界所有语种字符的编码方式,每个字符统一采用两个字节表示,其中unicode中英文字符的编码和ascii编码一致。
UTF-8:UTF-8 是一种变长的编码方式,一般用 1~4 个字节序列来表示 Unicode 字符,也是目前应用最广泛的一种 Unicode 编码方式。UTF-8 编码算法:首字节码用来区分采用的编码字节数 ,如果首字节以 0 开头,表示单字节编码;如果首字节以 110 开头,表示双字节编码;如果首字节以 1110 开头,表示三字节编码,后续每个字节高两位始终是10,以此类推。
例如:
字符‘a’ | 第一字节 | 第二字节 | 第三字节 |
---|---|---|---|
unicode编码 | 01100001 | - | - |
utf编码 | 0_1100001 | - | - |
字符‘啊’ | 第一字节 | 第二字节 | 第三字节 |
---|---|---|---|
unicode编码 | 01010101 | 01001010 | - |
utf编码 | 1110_0101 | 10_010101 | 10_001010 |
总结:由上我们得知,utf-8是unicode编码的一种压缩方式,用于在文字传输时减少网络带宽的占用,这两种编码使用一定的算法即可相互转化;而GBK和UNICODE是两种不同的编码方式,他们字节并没有算法可以实现的规律,所以只能使用查表的方式来实现。
UNICODE转UTF8:
由于在UNICODE编码中,ASCII编码高8位始终为0,所以使用一个字节即可表示,转化为UTF8编码不需要任何处理;而汉字的编码占用2个字节,转化为UTF8需要使用3个字节来表示,这里根据上述的编码方式来进行处理。
//参数:uni_in,要转码的Unicode编码地址,高字节在前 //参数:utf8_out,转码后输出的utf8编码存储地址的指针,在转码后地址自动向后移编 //返回值:下一个Unicode编码地址 u8 *uni2utf8 (const u8 *uni_in,u8 **utf8_out) { u16 c=0; if ((uni_in)&&(c=(uni_in[0]<<8)|uni_in[1],c)) { if (c<0x80) { **utf8_out=c; (*utf8_out)++; return (u8*)uni_in+2; } else { (*utf8_out)[0]=0xe0; (*utf8_out)[0]|=uni_in[0]>>4; (*utf8_out)[1]=0x80; (*utf8_out)[1]|=((uni_in[0]<<2)|(uni_in[1]>>6))&0x3f; (*utf8_out)[2]=0x80; (*utf8_out)[2]|=(uni_in[1])&0x3f; (*utf8_out)+=3; return (u8*)uni_in+2; } } return 0; }
UTF8转UNICODE:
//参数:utf8_in,要转码的UTF8编码地址,高字节在前 //参数:uni_out,转码后输出的uni编码存储地址的指针,在转码后地址自动向后移编 //返回值:下一个utf8编码地址 u8 *utf82uni (const u8 *uft8_in,u8 **uni_out) { if ((uft8_in)&&(*uft8_in)) { if (uft8_in[0]<0x80) { (*uni_out)[0]=0; (*uni_out)[1]=*uft8_in; (*uni_out)+=2; return (u8*)uft8_in+1; } else { (*uni_out)[0]=uft8_in[0]<<4; (*uni_out)[0]|=(uft8_in[1]>>2)&0x0f; (*uni_out)[1]=(uft8_in[1]<<6); (*uni_out)[1]|=(uft8_in[2])&0x3f; (*uni_out)+=2; return (u8*)uft8_in+3; } } return 0; }
GBK转UNICODE:
GBK和UNICODE之间的转化需要使用到编码对照表,其中英文只需要把高字节设为0直接赋值即可。
static int g_unigbk_size=0; //GBK编码转Unicode编码 //高字节在前 u8 *gbk2uni (u8 *gbk_in,u8 **uni_out) { u16 t[2]; u16 c; u32 i, li, hi; u16 n; unsigned int cout; u32 gbk2uni_offset=0; if (gbk_in==0||*gbk_in==0) return 0; if (*gbk_in < 0x80) { (*uni_out)[0]=0; //输出高字节在前 (*uni_out)[1]=*gbk_in; (*uni_out)+=2; return gbk_in+1; } else { c=(gbk_in[0]<<8)|gbk_in[1]; if(!g_unigbk_size) { // 打开编码对照表,得到编码对照表的大小 g_unigbk_size=unigbk_open(); } gbk2uni_offset=g_unigbk_size/2; if(g_unigbk_size)//存在 { /* Unicode to OEMCP */ hi=g_unigbk_size/2;//对半开. hi =hi / 4 - 1; li = 0; for (n = 16; n; n--) { i = li + (hi - li) / 2; //比较编码是否相等,相等则输出对应的UNICODE编码 cout=unigbk_read(i*4+gbk2uni_offset,&t,4); if (c == t[0]) break; if (c > t[0])li = i; else hi = i; } c = n ? t[1] : 0; }else c=0; (*uni_out)[0]=c>>8; //输出高字节在前 (*uni_out)[1]=c&0xff; *uni_out+=2; return gbk_in+2; } //return 0; }
UNICODE转GBK:
//Unicode编码转GBK编码 //高字节在前 u8 *uni2gbk (u8 *uni_in,u8 **gbk_out) { u16 t[2]; u16 c; u32 i, li, hi; u16 n; unsigned int cout; u32 gbk2uni_offset=0; if (uni_in==0||(c=(uni_in[0]<<8)|uni_in[1],c==0)) return 0; if (c < 0x80) { (*gbk_out)[0]=c; (*gbk_out)+=1; return uni_in+2; } else { if(!g_unigbk_size)//如果没打开UNIGBK.BIN. { g_unigbk_size=unigbk_open(); } gbk2uni_offset=0; //因为在编码表文件中是低字节在前,这里重新指定c //c=(uni_in[1]<<8)|uni_in[0]; if(g_unigbk_size)//存在 { /* Unicode to OEMCP */ hi=g_unigbk_size/2;//对半开. hi =hi / 4 - 1; li = 0; for (n = 16; n; n--) { i = li + (hi - li) / 2; cout=unigbk_read(i*4+gbk2uni_offset,&t,4); if (c == t[0]) break; if (c > t[0])li = i; else hi = i; } c = n ? t[1] : 0; }else c=0; (*gbk_out)[0]=c>>8; //输出高字节在前 (*gbk_out)[1]=c&0xff; *gbk_out+=2; return uni_in+2; } //return 0; }
编码对照表只需要实现两个函数:
int unigbk_open(void);
此函数用于打开编码对照表,返回表的大小,单位字节;
int unigbk_read(int off,void *buff,int size);
此函数用于读取给定偏移的表数据,单位字节。
以下实现的是一个在单片机中可用的编码对照表,可以使用SD卡中或flash中的编码对照表:
/* 1,use uingbk file from sd card; 2,use uingbk file from flash manager; 3,unigbk table from mcu flash */ #define UNIGBK_TYPE 2 #if UNIGBK_TYPE==1 static FIL *UK_FILE=0; static FILINFO *UK_FILINFO=0; static char UK_FLAG=0; //标记是否打开了UNIGBK.BIN static const char *UNIGBK_PATH="0:/SYS/UNIGBK.BIN"; //UNIGBK 存放路径 int unigbk_open(void) { if(!UK_FLAG)//如果没打开UNIGBK.BIN. { UK_FILE=malloc(sizeof(FIL)); UK_FILINFO=malloc (sizeof(UK_FILINFO)); if (f_stat((const TCHAR*)UNIGBK_PATH,UK_FILINFO)==FR_OK) { if(f_open(UK_FILE,(const TCHAR*)UNIGBK_PATH,FA_READ)!=FR_OK) { UK_FLAG=0; free(UK_FILE); free(UK_FILINFO); } else { UK_FLAG=1; return UK_FILINFO->fsize; } } else { UK_FLAG=0; free(UK_FILE); free(UK_FILINFO); return 0; } } if(UK_FILINFO) return UK_FILINFO->fsize; else return 0; } int unigbk_read(int off,void *buff,int size) { UINT br=0; if(UK_FILE) { f_lseek(UK_FILE,off); f_read(UK_FILE,buff,size,&br); } return br; } #elif UNIGBK_TYPE==2 static u8 UK_FLAG=0; static u32 g_uniTableOffset=0; static u32 g_uniTableSize=0; int unigbk_open(void) { if(!UK_FLAG)//如果没打开UNIGBK.BIN. { g_uniTableOffset=FLASH_FindFile("UNIGBK.BIN",&g_uniTableSize); if(g_uniTableOffset) { UK_FLAG=1; return g_uniTableSize; } else { UK_FLAG=0; return 0; } } if(g_uniTableOffset) return g_uniTableSize; else return 0; } int unigbk_read(int off,void *buff,int size) { UINT br=0; if(UK_FLAG) { br=FLASH_ReadData ((u8*)buff,g_uniTableOffset+off,size); } return br; }
链接:https://pan.baidu.com/s/1rnVFK0Bk–4ko5kSctTBdg
提取码:zngb
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。