1

我正在尝试将来自 .NET 的 unicode 字符串转换为本机 C++,以便我可以将它们写入文本文件。然后该过程将被反转,以便读取文件中的文本并将其转换为托管的 unicode 字符串。

我使用以下代码:

String^ FromNativeToDotNet(std::string value)
{
  // Convert an ASCII string to a Unicode String
  std::wstring wstrTo;
  wchar_t *wszTo = new wchar_t[lvalue.length() + 1];
  wszTo[lvalue.size()] = L'\0';
  MultiByteToWideChar(CP_UTF8, 0, value.c_str(), -1, wszTo, (int)value.length());
  wstrTo = wszTo;
  delete[] wszTo;

  return gcnew String(wstrTo.c_str());
}


std::string FromDotNetToNative(String^ value)
{ 
  // Pass on changes to native part
  pin_ptr<const wchar_t> wcValue = SafePtrToStringChars(value);
  std::wstring wsValue( wcValue );

  // Convert a Unicode string to an ASCII string
  std::string strTo;
  char *szTo = new char[wsValue.length() + 1];
  szTo[wsValue.size()] = '\0';
  WideCharToMultiByte(CP_UTF8, 0, wsValue.c_str(), -1, szTo, (int)wsValue.length(), NULL, NULL);
  strTo = szTo;
  delete[] szTo;

  return strTo;
}

发生的情况是,例如一个日文字符被转换为两个 ASCII 字符(汉 ->“w)。我认为这是正确的?但另一种方式不起作用:当我调用 FromNativeToDotNet wizh "w 我只得到 "w 作为托管unicode 字符串...如何正确恢复日文字符?

4

3 回答 3

3

最好使用 UTF8Encoding:

static String^ FromNativeToDotNet(std::string value)
{
    array<Byte>^ bytes = gcnew array<Byte>(value.length());
    System::Runtime::InteropServices::Marshal::Copy(IntPtr((void*)value.c_str()), bytes, 0, value.length());
    return (gcnew System::Text::UTF8Encoding)->GetString(bytes);
}


static std::string FromDotNetToNative(String^ value)
{ 
    if (value->Length == 0) return std::string("");
    array<Byte>^ bytes = (gcnew System::Text::UTF8Encoding)->GetBytes(value);
    pin_ptr<Byte> chars = &bytes[0];
    return std::string((char*)chars, bytes->Length);
}
于 2012-05-24T03:16:50.080 回答
2

一个日文字符被转换为两个 ASCII 字符(汉->“w)。我认为这是正确的?

不,那个字符,U+6F22,应该被转换成三个字节:0xE6 0xBC 0xA2

在 UTF-16(小端)中,U+6F22 以 0x22 0x6F 的形式存储在内存中,这看起来像"o在 ascii(而不是"w)中,所以看起来从 String^ 到 std::string 的转换有问题。

我对 String^ 不够熟悉,不知道从 String^ 转换为 std::wstring 的正确方法,但我很确定这就是你的问题所在。


我认为以下内容与您的问题没有任何关系,但这显然是错误的:

std::string strTo;
char *szTo = new char[wsValue.length() + 1];

你已经知道一个宽字符可以产生多个窄字符,所以宽字符的数量显然不一定等于或大于对应的窄字符的数量。

您需要使用 WideCharToMultiByte 来计算缓冲区大小,然后使用该大小的缓冲区再次调用它。或者您可以分配一个缓冲区来保存 3 倍于宽字符的字符数。

于 2012-05-23T15:55:59.577 回答
1

试试这个:

String^ FromNativeToDotNet(std::string value)
{
  // Convert a UTF-8 string to a UTF-16 String
  int len = MultiByteToWideChar(CP_UTF8, 0, value.c_str(), value.length(), NULL, 0);
  if (len > 0)
  {
    std::vector<wchar_t> wszTo(len);
    MultiByteToWideChar(CP_UTF8, 0, value.c_str(), value.length(), &wszTo[0], len);
    return gcnew String(&wszTo[0], 0, len);
  }

  return gcnew String((wchar_t*)NULL);
}

std::string FromDotNetToNative(String^ value)
{ 
  // Pass on changes to native part
  pin_ptr<const wchar_t> wcValue = SafePtrToStringChars(value);

  // Convert a UTF-16 string to a UTF-8 string
  int len = WideCharToMultiByte(CP_UTF8, 0, wcValue, str->Length, NULL, 0, NULL, NULL);
  if (len > 0)
  {
    std::vector<char> szTo(len);
    WideCharToMultiByte(CP_UTF8, 0, wcValue, str->Length, &szTo[0], len, NULL, NULL);
    return std::string(&szTo[0], len);
  }

  return std::string();
}
于 2012-05-24T01:21:27.327 回答