【问题标题】:why does mbstowcs return "invalid multibyte character"为什么 mbstowcs 返回“无效的多字节字符”
【发布时间】:2011-09-18 00:57:33
【问题描述】:

"קמ"ד חיר!" 是从 gdb 中的变量打印粘贴的输入字符串副本。调用 mbstowcs 返回 -1,而另一个输入为 NULL。关于问题出在哪里/如何解决这个问题的任何想法?

"\327\247\327\236"\327\223 \327\227\327\231\327\250!\000\000\000"是八进制非ascii字符的字符串

程序语言环境是 C。

【问题讨论】:

  • 我们需要字符串的十六进制转储,而不是复制粘贴的文本。如果复制并粘贴字符串,它不会保留二进制数据。
  • 你的程序在什么语言环境中?
  • mbstowcs 用于与您的运行时交互。如果您通过反序列化具有已知编码的源来获取字符串,则应使用 iconv 之类的东西,从已知编码改为 WCHAR_T。

标签: c++ c utf-8 utf-16


【解决方案1】:

mbtowcs 函数不处理 UTF-8 编码,没有您可以设置的语言环境让它将 UTF-8 转换为 wchar_t。因此,我将使用 Windows 示例,但总体思路在大多数操作系统上是相同的。

在多字节字符集的世界中,给定的八进制值可能没有一个含义,任何给定的字符也可能没有一个八进制值。特定八进制值的含义以及字符的表示方式(甚至 如果 可以表示)由locale 确定。

当 mbstowcs 返回错误时,它基本上是在告诉您没有与传入的多字节字符等效的宽字符。这可能意味着没有 UNICODE 字符(不太可能但并非不可能),或者可能意味着语言环境没有为给定的八进制值(或多字节字符的八进制值序列)定义字符。

如果您没有明确设置您的语言环境(通过调用setlocale),那么您将获得一个基于您的系统配置的语言环境。要检索您当前的语言环境,您可以致电_get_current_locale。一旦你知道了你的语言环境,你就可以确定一个特定的八进制值代表什么字符(如果有的话),然后你就可以确定 UNICODE 等价物是什么(如果有的话)。

识别问题字符的一种方法是改变传递给 mbstowcs 的长度,直到找到导致错误的单个字符。蛮力方法可能是从 length=1 开始并增加它直到 mbstowcs 返回 -1。

7 月 25 日更新

从 cmets 的讨论中,我们发现输入字符串(很可能)被编码为 UTF-8。虽然最初的答案是正确的(就目前而言),但还远远不够。在 Windows 上,您无法创建将处理以 UTF-8 编码的字符的语言环境。

当面对 UTF-8 时,我们可以使用代码页 CP_UTF8 调用 MultiByteToWideChar 而不是调用 mbtowcs,但该代码仅适用于 Windows...

BYTE bytes [] = {0xD7,0x99,0xD7,0x95,0xD7,0x97,0xD7,0x90,0xD7,0x99,0x20,0xD7,0x95,0xD7,0x9B,0xD7,0x98,0xD7,0xA8, 0x00};

int result;

// get length of converted string in characters
result = MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, (char *)bytes, 
    sizeof (bytes), NULL, 0);

wchar_t * name = new wchar_t [result];

// convert string
result = MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, (char *)bytes, 
    sizeof (bytes), name, result);

【讨论】:

  • 字符串实际上是通过facebook发送给我的,而不是本地生成的。那我怎么翻译呢?
  • mbstowcs 函数不知道(或不关心)正在翻译的字符串来自 Facebook。它所做的只是查看当前的语言环境设置并翻译字符串,就好像那是使用的编码一样。您需要弄清楚 Facebook 使用的是什么代码页,然后适当地设置您的语言环境。或者,更好的是,使用提供 UNICODE 字符串而不是多字节字符串的 Facebook API。这样一来,所使用的编码就毫无疑问,而且您不需要转换为宽字符。
  • api.facebook.com/1.0" xmlns:xsi="w3.org/2001/XMLSchema-instance" list="true"> 1000000220633150xD7 0x99 0xD7 0x95 0xD7 0x97 0xD7 0x90 0xD7 0x99 0x20 0xD7 0x95 0xD7 0x9B 0xD7 0x98 0xD7 0xA8 来自facebook> .不知何故,IE/Firefox 正确地显示了数据。代码页是否在此处指定?
  • 看起来 的内容可能以 UTF-8 编码。您是否希望名称为“יוחאי וכטר”
  • 是的,但你不是说我需要一个语言环境吗?
【解决方案2】:

我敢打赌,如果您像这样设置 UTF-8,它会起作用:

setlocale(LC_CTYPE, "UTF-8");

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2011-04-11
  • 2021-10-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-01
相关资源
最近更新 更多