需要将字符串转换为 UTF8 字符串

Required to convert a String to UTF8 string

问题陈述: 我需要将生成的字符串转换为 UTF8 字符串,此生成的字符串具有扩展的 ascii 字符并且我在 Linux 系统上 (2.6.32-358.el6.x86_64)。

A POC is still in progress so I can only provide small code samples and complete solution can be posted only once ready.

为什么我需要 UFT8(我扩展了 ascii 字符以存储在必须为 UTF8 的字符串中)。

我是如何进行的:

请看下面的示例代码

int main(){
  char  CharString[] = "Prova";
  iconv_t cd;
  wchar_t  WcharString[255];

  size_t size= mbstowcs(WcharString, CharString, strlen(CharString));

  wprintf(L"%ls\n", WcharString);

  wprintf(L"%s\n", WcharString);

  printf("\n%zu\n",size);
}

这里有一个问题:

输出为

Prova?????

s

  1. 为什么这里没有打印尺寸?
  2. 为什么第二个 printf 只打印一个字符。
  3. 如果我在两个打印字符串之前都打印大小,那么只会打印 5 个字符串,并且两个字符串都从控制台中丢失。


继续第二部分:

现在我将有一个 wchar_t 字符串,我想将它转换为 UTF8 字符串

为此,我正在网上冲浪,发现 iconv 会在这里提供帮助。

在这里提问 这些是我在 manual

中找到的方法
**iconv_t iconv_open(const char *, const char *);

size_t  iconv(iconv_t, char **, size_t *, char **, size_t *);

int     iconv_close(iconv_t);**

在提供给 iconv 之前,我是否需要将 wchar_t 数组转换回 char 数组?

请就以上问题提出建议。

我正在谈论的扩展 ascii 请看下面标记的快照中的字母 i

对 utf8 使用 iconv 不是个好主意。自己实现utf8的定义就行了。这在描述 https://en.wikipedia.org/wiki/UTF-8 中用 C 很容易完成。 您甚至不需要 wchar_t,只需为您的角色使用 uint32_t。 如果您自己实现,您将学到很多东西,并且您的程序将因不使用 mb 或 iconv 函数而提高速度。

关于您的第一个问题(我将其解释为"why is all the output not what I expect"):

  1. '??????'在哪里come from? 在调用 mbstowcs(WcharString, CharString, strlen(CharString)) 中,最后一个参数 (strlen(CharString)) 是 output buffer 的长度,而不是输入字符串。 mbstowcs 不会写入超过该数量的宽字符,包括 NUL 终止符。由于转换需要 6 个宽字符,包括终止符,而您只允许它写入 5 个宽字符,因此生成的宽字符串不会以 NUL 终止,当您尝试打印它时,您最终会在结束后打印垃圾转换后的字符串。因此 ?????。您应该改用 wchar_t 中的输出缓冲区大小(在本例中为 255)。

  2. 为什么第二个wprintf只打印一个字符?当你用宽字符串参数调用wprintf时,你必须使用 %ls 格式代码(或者更准确地说,%s 转换需要使用 l 长度修饰符来限定)。如果你使用 %s 而没有 l,那么 wprintf 会将字符串解释为 char*,并且它会在输出时将每个字符转换为 wchar_t它。但是,由于参数实际上是一个宽字符串,所以字符串中的第一个 wchar_tL"p",这是某个整数大小的数字 0x70。这意味着 wchar_t 的第二个字节(从末尾开始计数,因为你有一个小端架构)是一个 0,所以如果你把这个字符串当作 个字符的字符串 ,它会在p之后立即终止。所以只打印一个字符。

  3. 为什么最后一个 printf 不打印任何东西? 在 C 中,输出流可以是 宽streambyte stream,但您在打开流时未指定。 (而且,无论如何,标准输出已经为您打开。)这称为流的 方向 。新打开的流是无方向的,第一次输出到流时方向是固定的。如果第一个输出调用是宽调用,如wprintf,则该流是宽流;否则,它是一个字节流。一旦设置,方向就固定了,你不能使用错误方向的输出调用。所以 printf 是非法的,它只会引发错误。


现在,让我们继续讨论您的第二个问题:我该怎么办?

首先你要清楚输入的是什么格式,你想怎么输出。在 Linux 上,您不太可能会想要使用 wchar_t。输入字符串最可能的情况是它已经是 UTF-8,或者它是某种 ISO-8859-x 编码。输出的最可能情况是相同的:要么是 UTF-8,要么是某种 ISO-8859-x 编码。

不幸的是,您的程序无法知道控制台期望的编码。输出甚至可能不会转到控制台。同样,您的程序实际上无法知道输入字符串中使用的是哪种 ISO-8859-x 编码。 (如果它是字符串文字,则可能会在调用编译器时指定编码,但没有提供信息的标准方式。)

如果您因为非 ascii 字符无法正确显示而无法查看输出,您应该首先确保控制台配置为使用与程序输出相同的编码。如果程序将 UTF-8 发送到显示 ISO-8859-15 的控制台,则文本将无法正确显示。理论上,您的语言环境设置包括控制台使用的编码,但如果您使用的是远程控制台(例如,通过 Windows 机器上的 PuTTY),那么控制台不是 Linux 的一部分环境和默认语言环境可能不正确。最简单的修复方法是正确配置您的控制台,但也可以更改 Linux 语言环境。

您使用 mbstowcs 来自字节字符串的事实表明您认为原始字符串是 UTF-8 格式的。因此,问题似乎不太可能是您需要将其 转换为 UTF-8.

您当然可以使用 iconv 将字符串从一种编码转换为另一种编码;您无需通过 wchar_t 即可。但是您确实需要知道实际的输入编码和所需的输出编码。