【问题标题】:Required to convert a String to UTF8 string需要将字符串转换为 UTF8 字符串
【发布时间】:2015-09-04 06:43:38
【问题描述】:

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

POC 仍在进行中,因此我只能提供少量代码示例 完整的解决方案只有在准备好后才能发布。

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

我是如何进行的:

  • 将生成的字符串转换为 wchar_t 字符串。

请看下面的示例代码

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);
}

这里有一个问题:

输出是

普罗瓦?????

s

  1. 为什么这里没有打印尺寸?
  2. 为什么第二个 printf 只打印一个字符。
  3. 如果我在两个打印字符串之前打印 size,则只打印 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

【问题讨论】:

  • 不是wprintf(L"s\n", WcharString); 应该是wprintf(L"%s\n", CharString); 还是什么?
  • 部分相关:在 Linux 上几乎没有人使用wchar_t,但所有字符串通常都是以 UTF-8 编码的窄字符串 (char *);您是明确选择使用wchar_t(如果是,为什么?)还是您正在使用的某个库要求使用它?
  • 您输入的扩展ASCII是什么意思?它是一个字节数组,其中每个字节对应一个字符,即使对于 128 及以上的值也是如此?那你为什么要使用wchar_t?一个简单的表格,其中包含 256 个条目的相应 UTF-8 字节序列,您就完成了。
  • @SouravGhosh 是的,如果我把屏幕截图放在这里,我错过了,
  • 没有“扩展ascii”之类的东西。

标签: c++ c utf-8 iconv wchar-t


【解决方案1】:

对于您的第一个问题(我将其解释为“为什么所有输出都不是我所期望的”):

  1. “??????”来自? 在调用mbstowcs(WcharString, CharString, strlen(CharString)) 中,最后一个参数(strlen(CharString)) 是输出缓冲区 的长度,而不是输入字符串的长度。 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,所以如果你把字符串当作 characters 的字符串,它将在p 之后立即终止。所以只打印一个字符。

  3. 为什么最后一个 printf 不打印任何内容?在 C 中,输出流可以是宽流字节流,但您在打开流时没有指定。 (而且,无论如何,标准输出已经为您打开了。)这称为流的orientation。新打开的流是无方向的,当您第一次输出到流时,方向是固定的。如果第一个输出调用是宽调用,比如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 进行操作。但是您确实需要知道实际的输入编码和所需的输出编码。

【讨论】:

  • 非常感谢。这是我所期待的一个可以深入和详细地告诉我的人,你的最后一个建议似乎非常好。无论发生什么,我都会这样做并在这里发布。是的,你没看错我正在通过腻子连接:) 再次感谢你。
【解决方案2】:

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

【讨论】:

  • 要输出字符串,OP 仍然需要wchar_t(这里——嘿!再说一遍,这很重要,但帖子中没有提到!——我猜他在 Windows 上)。但我同意 UTF8 的实现非常简单。
  • 大多数人认为 UTF8 是一种魔法,但它只是一种简单的编码,只留下 7 位 ascii 并编码其余的 24 位 unicode 值。如果你真的需要 wchar_t 输出取决于你想要编码的编码。但是如果你问我,我会简单地丢弃任何仍然使用旧字符表的系统。使用 gcc,我认为 wchar_t 在 x86_84 上被定义为 int
猜你喜欢
  • 2014-01-29
  • 1970-01-01
  • 2010-12-04
  • 1970-01-01
  • 2020-10-11
  • 1970-01-01
  • 2011-02-11
  • 1970-01-01
  • 2012-02-01
相关资源
最近更新 更多