从char*创建UTF-16字符串

Create UTF-16 string from char*

本文关键字:UTF-16 字符串 创建 char      更新时间:2023-10-16

所以我有标准的C字符串:

char* name = "Jakub";

我想把它转换成UTF-16。我发现,UTF-16的长度将是的两倍——一个字符需要两个字符。所以我创建了另一个字符串:

char name_utf_16[10];  //"Jakub" is 5 characters

现在,我相信对于ASCII字符,我将只使用较低的字节,所以对于所有这些字符,它将像74 00对应J,等等。有了这个信念,我可以写出这样的代码:

void charToUtf16(char* input, char* output, int length) {
    /*Todo: how to check if output is long enough?*/
    for(int i=0; i<length; i+=2)  //Step over 2 bytes
    {
        //Lets use little-endian - smallest bytes first
        output[i] = input[i];
        output[i+1] = 0;  //We will never have any data for this field
    }
}

但是,在这个过程中,我以"Jkb"结束。我知道没有办法正确地测试-我刚刚将字符串发送到Minecraft Bukkit服务器。断开连接后显示如下:

13:34:19 [INFO]断开连接jkb??[/127.0.0.1:53215]:服务器过时了!

注意:我知道Minecraft使用大端dian。上面的代码只是一个例子,事实上,我已经在类中实现了我的转换。

在我回答你的问题之前,请考虑一下:

这个编程领域充满了陷阱。理解ASCII, UTF7/8和ANSI/'多字节字符串(MBCS)'之间的差异是很有意义的,所有这些对于讲英语的程序员来说看起来和感觉都是一样的,但是如果它们被介绍给欧洲或亚洲用户,则需要非常不同的处理。

ASCII:字符范围是32 ~ 127。只有一个字节。线索就在名字里,它们对美国人很好,但不适用于世界其他地方。

ANSI/MBCS:这就是"代码页"的原因。字符32-127与ASCII相同,但也可以使用128-255范围内的字符作为附加字符,128-255范围中的一些字符可以用作标志,以标记该字符继续进入第二个、第三个甚至第四个字节。要正确处理字符串,您需要字符串字节和正确的代码页。如果您尝试使用错误的代码页处理字符串,您将没有正确的字符,并且错误地解释字符是1,2甚至4字节字符。

UTF7/8:这些是21位unicode字符点的8位宽格式化。在UTF-7和UTF-8中,unicode字符的长度可以在一到四个字节之间。与ANSI/MBCS相比,UTF编码的优点是没有由代码页引起的歧义。每个文字中的每个字形都有一个唯一的unicode码点,这意味着不可能通过在不同的计算机上用不同的区域设置解释数据来混淆字符集。

那么开始回答你的问题:

  1. 当你假设你的char*将只指向一个ASCII字符串时,这是一个非常危险的选择,用户控制输入的数据,而不是程序员。Windows程序将默认将其存储为MBCS。

  2. 你正在做的第二个假设是UTF-16编码将是8位编码的两倍大小。这通常不是一个安全的假设。根据源编码的不同,UTF-16编码可能是两倍的大小,也可能小于两倍的大小,在一个极端的例子中,长度实际上可能更短。

那么,安全的解决方案是什么呢?

安全的选择是在内部将应用程序实现为unicode。在windows上,这是一个编译器选项,这意味着您的windows控件都使用wchar_t*字符串作为它们的数据类型。在linux上,我不太确定您是否总是可以使用统一图形和操作系统库。您还必须使用wcslen()函数来获取字符串的长度等。当您与外部世界交互时,使用精确的字符编码。

要回答你的问题,然后变成改变问题,当我收到非UTF-16数据时,我该怎么办?

首先,要非常清楚你对它的格式做了什么假设?其次,接受有时转换到UTF-16可能会失败的事实。

如果您清楚源格式,那么您可以选择适当的win32或stl转换器来转换格式,然后在使用结果之前查找转换失败的证据。例如windows上的mbstowcs in或MultiByteToWideChar()。然而,安全地使用这两种方法意味着你需要理解上述所有答案。

所有其他选择都会带来风险。使用mbcs字符串,您将使用一个代码页输入数据字符串,并使用不同的代码页处理数据字符串。假设是ASCII数据,当你遇到一个非ASCII字符时,你的代码就会中断,你会把你的缺点"归咎于"用户。

为什么你想做你自己的Unicode转换功能,当有现有的C/c++函数,如<cstdlib>中包含的mbstowcs()

如果你仍然想做你自己的东西,那么看看Unicode联盟的开源代码,可以在这里找到:

在Windows和Linux下转换UTF-16到UTF-8,在C

output[i] = input[i];

这将分配输入的每个其他字节,因为您将i增加2。所以你得到"Jkb"也就不足为奇了。你可能想写:

output[i] = input[i / 2];