研究了一段时间的iconv.h,终于在查看资料和实践下搞定了iconv这个函数,实现了对包含错误编码的字符串的转码。常见的情况就是,某些字符不属于GBK字符集,而将这个字符串由GBK转到UTF-8的时候就会出错。
int convert(const char *from, /*要转换的字符集*/ const char *to, /*要转换到的字符集*/ char* save, /*输出字符串*/ int savelen, /*输出字符串缓存长度*/ char *src, /*源字符串*/ int srclen) /*源字符串长度*/ { iconv_t cd; char *inbuf = src; char *outbuf = save; size_t outbufsize = savelen; int status = 0; size_t savesize = 0; size_t inbufsize = srclen; char* inptr = inbuf; size_t insize = inbufsize; char* outptr = outbuf; size_t outsize = outbufsize; cd = iconv_open(to, from); iconv(cd,NULL,NULL,NULL,NULL); if (inbufsize == 0) { status = -1; goto done; } while (insize > 0) { size_t res = iconv(cd,&inptr,&insize,&outptr,&outsize); if (res == (size_t)(-1)) { if (errno == EILSEQ) { inptr ++; status = -3; } else if (errno == EINVAL) { break; } else if (errno == E2BIG) { status = -5; goto done; } else { status = -6; goto done; } } } if (outptr != outbuf) { int outsize = outptr - outbuf; strncpy(save+savesize, outbuf, outsize); } status = strlen(save); done: iconv_close(cd); return status; }
使用方法:
gchar *convert(gchar *from) { char *result = g_new(char, strlen(from) * 3 + 1); convert2("GBK", "UTF-8", result, strlen(from) * 3 + 1, from, strlen(from)); if (result != NULL) return result; else return ""; }
PS:iconv参考说明:
iconv函数族的头文件是iconv.h,使用前需包含之。
#include
iconv函数族有三个函数,原型如下:
(1)iconv_t iconv_open(const char *tocode,const char *fromcode);
此函数说明将要进行哪两种编码的转换,tocode是目标编码,fromcode是原编码,该函数返回一个转换句柄,供以下两个函数使用。
(2)size_t iconv(iconv_t cd,char **inbuf,size_t *inbytesleft,char **outbuf,size_t *outbytesleft);
此函数从inbuf中读取字符,转换后输出到outbuf中,inbytesleft用以记录还未转换的字符数,outbytesleft用以记录输出缓冲的剩余空间。
参数cd必须是由iconv_open函数创建的转换描述符。
大部分情形是inbuf 不为NULL,*inbuf也不为NULL。这种情况下,iconv函数将以*inbuf起始的多字节序列转换到以*outbuf起始的多字节序列。从*inbuf开始读取,最多*inbytesleft字节,转换后,从*outbuf开始写入,最多*outbytesleft字节。
iconv函数一次转换一个多字节字符,每次字符转换,*inbuf增加已转换的字节数,*inbytesleft相应地减少已转换的字节数;对应地,*outbuf和*outbytesleft作相应的修改,同时修改cd的转换状态。
以下四种情况不能完成转换:
1.输入中含无效的多字节序列。此时,它将errno设置为EILSEQ并返回(size_t)(-1)。*inbuf指向无效序列的最左端。
2.输入的字节序列已经全部被转换过,也就是*inbytesleft减少至0。此时,iconv返回本次调用中完成转换的数目(可逆的转换不计入)。
3.输入中以不完整多字节序列作结尾。此时,它将errno设置为EINVAL并返回(size_t)(-1)。*inbuf指向不完整多字节序列的最左端。
4.输出缓存区没有足够空间来存储下一个字符。此时,它将errno设置为E2BIG并返回(size_t)(-1)。
另一种情形是inbuf 为NULL或*inbuf为NULL,但*outbuf 不为NULL,*outbuf也不为NULL。这种情况下,iconv函数试图将cd的转换状态设置为初始状态并store a corresponding shift sequence at *outbuf。从*outbuf开始,最多写入*outbytesleft字节。如果输出缓存区没有足够空间来存储这个重置后的序列,他将errno设置为E2BIG并返回(size_t)(-1)。反之,*outbuf增加写入的字节数和*outbytesleft减少写入的字节数。
第三种情形是inbuf 为NULL或*inbuf为NULL,*outbuf 为NULL或*outbuf为NULL。这种情况下,iconv函数试图将cd的转换状态设置为初始状态。
返回值
iconv函数返回本次调用中转换的字符数,可逆的转换不计入。出错时,它将修改errno并返回(size_t)(-1)。
错误
除了其它错误以外,出现以下错误:
E2BIG
*outbuf没有足够的空间。
EILSEQ
输入含无效的多字节序列。
EINVAL
输入含不完整多字节序列。
(3)int iconv_close(iconv_t cd);
此函数用于关闭转换句柄,释放资源。