您如何正确使用WideCharToMultiByte


70

我已经阅读了WideCharToMultiByte上的文档,但仍受此参数限制:

lpMultiByteStr
[out] Pointer to a buffer that receives the converted string.

我不太确定如何正确初始化变量并将其输入到函数中


25
您似乎有什么理由要问但不接受答案呢?在这些网站上,通常的做法是用反馈来奖励良好的答案,以表彰人们投入时间来回答您的问题。您在下面得到了一些很好的答案...(轻推)
阿萨德·易卜拉欣

Answers:


139

这是几个函数(基于Brian Bondy的示例),这些函数使用WideCharToMultiByte和MultiByteToWideChar使用utf8在std :: wstring和std :: string之间进行转换,以免丢失任何数据。

// Convert a wide Unicode string to an UTF8 string
std::string utf8_encode(const std::wstring &wstr)
{
    if( wstr.empty() ) return std::string();
    int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL);
    std::string strTo( size_needed, 0 );
    WideCharToMultiByte                  (CP_UTF8, 0, &wstr[0], (int)wstr.size(), &strTo[0], size_needed, NULL, NULL);
    return strTo;
}

// Convert an UTF8 string to a wide Unicode String
std::wstring utf8_decode(const std::string &str)
{
    if( str.empty() ) return std::wstring();
    int size_needed = MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0);
    std::wstring wstrTo( size_needed, 0 );
    MultiByteToWideChar                  (CP_UTF8, 0, &str[0], (int)str.size(), &wstrTo[0], size_needed);
    return wstrTo;
}

9
应当指出,在C ++ 11之前,不能保证std :: string和std :: wstring的内存是连续的。
Chris_F 2014年

5
我严重怀疑是否存在没有连续向量的市售stl实现。在第一下不是必需的连续存储器的事实++规范是一个监督:herbsutter.com/2008/04/07/...
tfinniga

3
@tfinniga先前的评论是关于字符串,而不是向量。尽管在现实世界中所有实现都使字符串连续,但不能保证在C ++ 98中字符串是连续的(不是Sutter引用的结果)。
user4815162342

2
保证@Swift c_str()返回指向连续缓冲区的指针,但是在C ++ 11之前,这不能保证与字符串的内部表示形式相同。
Chris_F '16

2
这如何处理非英语字母,例如斯堪的纳维亚ÅåÄääööÆæØø?从我可以看到它变得乱码。:-(
比约恩·拉尔森

36

详细说明Brian R. Bondy提供的答案:以下示例说明了为什么不能简单地将输出缓冲区的大小调整为源字符串中宽字符的数量:

#include <windows.h>
#include <stdio.h>
#include <wchar.h>
#include <string.h>

/* string consisting of several Asian characters */
wchar_t wcsString[] = L"\u9580\u961c\u9640\u963f\u963b\u9644";

int main() 
{

    size_t wcsChars = wcslen( wcsString);

    size_t sizeRequired = WideCharToMultiByte( 950, 0, wcsString, -1, 
                                               NULL, 0,  NULL, NULL);

    printf( "Wide chars in wcsString: %u\n", wcsChars);
    printf( "Bytes required for CP950 encoding (excluding NUL terminator): %u\n",
             sizeRequired-1);

    sizeRequired = WideCharToMultiByte( CP_UTF8, 0, wcsString, -1,
                                        NULL, 0,  NULL, NULL);
    printf( "Bytes required for UTF8 encoding (excluding NUL terminator): %u\n",
             sizeRequired-1);
}

并输出:

Wide chars in wcsString: 6
Bytes required for CP950 encoding (excluding NUL terminator): 12
Bytes required for UTF8 encoding (excluding NUL terminator): 18

一个很好的示例,说明了代码页/编码转换的一个重要且经常被忽略的方面!
约翰·杰雷尔

-1 OP寻求有关lpMultiByteStr参数的帮助。这个答案不是在回答OP,而是与另一个已发布答案的切线。
错误454

3
@ Error454:他们在2008年没有评论。只需对其进行标记。
Ry-

+1表示排除null,返回的sizeRequired包含空格,因此lpMultiByteStr的正确初始化必须考虑到这一点
Les

20

您可以通过创建新的char数组来使用lpMultiByteStr [out]参数。然后,您将这个char数组传递进去以填充它。您只需要初始化字符串的长度+ 1,以便在转换后可以有一个以空终止的字符串。

这里有几个有用的帮助函数,它们显示了所有参数的用法。

#include <string>

std::string wstrtostr(const std::wstring &wstr)
{
    // Convert a Unicode string to an ASCII string
    std::string strTo;
    char *szTo = new char[wstr.length() + 1];
    szTo[wstr.size()] = '\0';
    WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), -1, szTo, (int)wstr.length(), NULL, NULL);
    strTo = szTo;
    delete[] szTo;
    return strTo;
}

std::wstring strtowstr(const std::string &str)
{
    // Convert an ASCII string to a Unicode String
    std::wstring wstrTo;
    wchar_t *wszTo = new wchar_t[str.length() + 1];
    wszTo[str.size()] = L'\0';
    MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, wszTo, (int)str.length());
    wstrTo = wszTo;
    delete[] wszTo;
    return wstrTo;
}

-

在文档中的任何时候,当您看到它都有一个指向类型的指针的参数,并且告诉您它是一个out变量时,您将需要创建该类型,然后将其传递给它。该函数将使用该指针填充变量。

这样您可以更好地理解这一点:

//pX is an out parameter, it fills your variable with 10.
void fillXWith10(int *pX)
{
  *pX = 10;
}

int main(int argc, char ** argv)
{
  int X;
  fillXWith10(&X);
  return 0;
}

5
该代码应考虑到多字节char字符串中所需的字节数可能大于宽字符串中的字符数。单个宽字符可能会在多字节char字符串中导致2个或更多字节,具体取决于所涉及的编码。
Michael Burr

以亚洲字符为例,但这实际上取决于转换所使用的代码页。在您的示例中,这可能不是问题,因为任何非ANSI字符都将被问号代替。
HS。

3
若要获取转换所需的大小,请使用0作为目标缓冲区的大小来调用WideCharToMultiByte。然后它将返回目标缓冲区大小所需的字节数。
HS。

是否有便携式的方式(即POSIX)来做到这一点?WideCharToMultiByte是Windows函数。
哈维

使用gb2312之类的代码时,此代码中断了字节数或宽字符数计数。
青铜人
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.