iOS 使用C下的iconv方法对Emoji表情转码,从UTF8到GBK,带表情字符串转码后返回结果为空,的解决办法。

时间:2021-03-24 08:43:21

我们的项目需要通过C语言的socket方式实现在iOS手机端与pc端,安卓端的实施文字信息收发。而iOS的字符串转化为C的string的时候默认初始格式是UTF8String,考虑到和PC和安卓的协调(初期确定的都是使用GBK来做文字信息交互的)。在iOS大范围出现了emoji表情的时候,问题出现了,原本的UTF8String转GBK的方法在处理字符串中带有表情的字符串的时候会使字符串转换结果为空,之前的解决方案是通过unicode码来过滤字符串中的表情。而现在需求要求还是要兼容emoji表情发送和显示。所以考虑让转码支持emoji表情。


解决办法:在转码的时候,原本使用的是从“UTF-8” 转 “GBK”的,会出现上面的问题,转码结果为空。从“UTF-8” 转 “GB2312”,还是同样的问题。之后尝试了在iOS语言下转gbk再转成C的字符串,还是失败。有一个曲线救国的方法,是在转成UTF-8之前先转成ASCII码,然后在转,收到时在从GBK转回UTF-8之后,再把他用ASCII码转换一次,就可以正常显示。

当然最完美的解决办法是使用“GB18030”,这是最新版的汉子编码,基本完全向下兼容GB2312和GBK格式,也兼容emoji格式。关于GBK,GB2312和GB18030的关系可以参考链接

具体的代码如下:

int nRet = iconv_string("UTF-8", "GB18030", (char*)tFont.sCharContent.c_str(), tFont.sCharContent.size(), sValue[6], 1200);

int iconv_string(const char *from, const char *to,
char *src, size_t len,
string& result,
size_t buf_size)
{
iconv_t cd;

char *pinbuf(src);
size_t inbytesleft(len);
char *poutbuf(0);
buf_size = buf_size > len*2 ? buf_size : len*2;

char *dst(0);
size_t retbytes(0);
//bool done(false);
int errno_save(0);

if ((iconv_t)-1 == (cd = iconv_open(to, from)))
{
return -1;
}

vector<char> buffer(buf_size);
size_t outbytesleft(buffer.size());
dst = &buffer[0];
result.clear();
poutbuf = dst;

retbytes = iconv(cd, &pinbuf, &inbytesleft, &poutbuf, &outbytesleft);

errno_save = 1;

if (dst != poutbuf)
{
// we have something to write
result.append(dst, poutbuf-dst);
}

if (retbytes != (size_t)-1)
{
poutbuf = dst;
outbytesleft = buf_size;
(void)iconv(cd, NULL, NULL, &poutbuf, &outbytesleft);

if (dst != poutbuf)
{// we have something to write
result.append(dst, poutbuf-dst);
}

errno_save = 0;
}

iconv_close(cd);
//errno = errno_save;
return (errno_save) ? -1 : 0;
}