gpt4 book ai didi

c - 使用 iconv 进行简单的 UTF8->UTF16 字符串转换

转载 作者:太空狗 更新时间:2023-10-29 15:55:30 25 4
gpt4 key购买 nike

我想编写一个函数将 UTF8 字符串转换为 UTF16(小端)。问题是,iconv 函数似乎没有让您提前知道您需要多少字节来存储输出字符串。

我的解决方案是从分配 2*strlen(utf8) 开始,然后循环运行 iconv,使用 realloc 增加该缓冲区的大小 如有必要:

static int utf8_to_utf16le(char *utf8, char **utf16, int *utf16_len)
{
iconv_t cd;
char *inbuf, *outbuf;
size_t inbytesleft, outbytesleft, nchars, utf16_buf_len;

cd = iconv_open("UTF16LE", "UTF8");
if (cd == (iconv_t)-1) {
printf("!%s: iconv_open failed: %d\n", __func__, errno);
return -1;
}

inbytesleft = strlen(utf8);
if (inbytesleft == 0) {
printf("!%s: empty string\n", __func__);
iconv_close(cd);
return -1;
}
inbuf = utf8;
utf16_buf_len = 2 * inbytesleft; // sufficient in many cases, i.e. if the input string is ASCII
*utf16 = malloc(utf16_buf_len);
if (!*utf16) {
printf("!%s: malloc failed\n", __func__);
iconv_close(cd);
return -1;
}
outbytesleft = utf16_buf_len;
outbuf = *utf16;

nchars = iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft);
while (nchars == (size_t)-1 && errno == E2BIG) {
char *ptr;
size_t increase = 10; // increase length a bit
size_t len;
utf16_buf_len += increase;
outbytesleft += increase;
ptr = realloc(*utf16, utf16_buf_len);
if (!ptr) {
printf("!%s: realloc failed\n", __func__);
free(*utf16);
iconv_close(cd);
return -1;
}
len = outbuf - *utf16;
*utf16 = ptr;
outbuf = *utf16 + len;
nchars = iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft);
}
if (nchars == (size_t)-1) {
printf("!%s: iconv failed: %d\n", __func__, errno);
free(*utf16);
iconv_close(cd);
return -1;
}

iconv_close(cd);
*utf16_len = utf16_buf_len - outbytesleft;

return 0;
}

这真的是最好的方法吗?重复的 realloc 似乎很浪费,但不知道 utf8 中可能有哪些字符序列,以及它们在 utf16 中会产生什么结果,我不知道我是否可以更好地猜测初始缓冲区大小大于 2*strlen(utf8)

最佳答案

这是使用 iconv 的正确方法。

请记住,iconv 旨在能够从任意字符编码重新编码为另一种任意字符编码。它支持任意组合。鉴于此,基本上只有两种方法可以知道输出需要多少空间:

  1. 猜一猜。进行转换,并在必要时增加您的猜测。
  2. 进行两次转换。第一次,只是计数,丢弃输出。分配您计算的总空间量,然后再次进行转换。

首先是您的工作。第二个显然有你必须做两次工作的缺点。 (顺便说一句,您可以使用 iconv 的第二种方法,即在局部变量中使用暂存器缓冲区作为第一遍的输出缓冲区。)

真的没有别的办法了。要么您事先知道输入中有多少个字符(不是字节),以及其中有多少在/不在 BMP 中;或者你没有,你必须计算它们。

在这种情况下,您碰巧提前知道输入和输出编码是什么。如果您在开始之前自己对输入字符串进行一些 UTF-8 操作,您可以更好地猜测您需要的输出缓冲区空间量。这有点像上面的第二个选项,但更优化,因为必要的 UTF-8 体操不像成熟的 iconv 那样昂贵。

不过,我建议您不要这样做。你仍然会对输入字符串进行两次传递,所以你不会节省那么多,你需要编写更多的代码,并且它引入了一个错误的可能性,如果体操不太对。

我什至不打算描述体操,因为它真正的意义或多或少是实现一个 UTF-8 解码器,虽然它的核心只是一些简单的位掩码和移位的情况,但是与拒绝无效序列相关的详细信息,这些序列很容易以具有安全隐患的方式出错。所以不要这样做。

关于c - 使用 iconv 进行简单的 UTF8->UTF16 字符串转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13297458/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com