多平台的方法来转换 std::string 和 std::wstring 之间的格式

3

我目前正在使用Windows API的方法MultiByteToWideCharWideCharToMultiByte来在std::stringstd::wstring之间进行转换。

我正在将我的代码从Windows依赖中移除,因此我想知道上述方法的替代方法。具体来说,使用Boost将是很棒的选择。我可以使用哪些方法?以下是我目前正在使用的代码:

const std::wstring Use::stow(const std::string& str)
{
    if (str.empty()) return L"";
    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;
}

const std::string Use::wtos(const std::wstring& wstr)
{
    if (wstr.empty()) return "";
    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;
}

1
标准库中的 std::mbstowcsstd::wcstombs 怎么样? - Some programmer dude
1
这可能比仅仅查找转换函数更加复杂,请参见此处 - Wilbert
哎呀!我不知道那个! - Didac Perez Parera
3个回答

5
基本上使用<cstdlib>,您可以采用与Joachim Pileborg提到的类似的实现。只要将区域设置为所需的任何内容(例如:setlocale(LC_ALL,"en_US.utf8");MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0) => mbstowcs(nullptr, data(str), size(str)) MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), &wstrTo[0], size_needed) => mbstowcs(data(wstrTo), data(str), size(str))

WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL) => wcstombs(nullptr, data(wstr), size(wstr))

WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), &strTo[0], size_needed, NULL, NULL) => wcstombs(data(strTo), data(wstr), size(wstr))

编辑:

要求字符串是连续分配的, 如果您正在编译跨平台应用程序,这可能非常重要,因为以前的标准要求string是连续分配的。以前调用&str[0], &strTo[0], &wstr[0], 或者&wstrTo[0]可能会导致问题。
由于现在是被接受的标准,我已经改进了我的建议替代方案,使用data而不是引用字符串的前面。


嗨,乔纳森,它已经起作用了!你认为我使用这种方法会遇到内存错误吗?我担心内存分配。 - Didac Perez Parera
1
为什么不使用str.c_str()而使用&str[0]呢?它肯定是连续的。 - Julien
1
是的,我相信@Julien的建议对于提供的源字符串将起作用c_str()std::wstring一起使用,但对于目标字符串则不起作用。对于目标字符串,我的初始想法是您应该临时分配一个向量,然后将其复制到字符串中。因此,在wtos中可以这样做:std::vector< char > temp( size_needed, '\0' ); std::wcstombs( &*temp.begin(), wstr.c_str(), wstr.size() ); std::string strTo( size_needed, '\0' ); std::copy( strTo.begin(), strTo.end(), temp.begin() ); 这可能会成为一个很好的后续问题! - Jonathan Mee
1
这是一个在跨平台的常见代码中实现的好方法。如果它仍然需要在Windows上运行,您需要添加_CRT_SECURE_NO_WARNINGS预处理器宏。否则,它会抱怨您没有使用特定于Windows的mbstowcs_s函数。 - spfursich

0

从您的代码来看,您正在使用utf-8编码。要使用utf-8,请查看http://utfcpp.sourceforge.net/上的UTF8-CPP,这是一个仅包含头文件的库。

查看utf8to32函数。(请注意,Windows上的wchar_t为16位,在其他平台如Linux上通常为32位)


-1
const std::wstring Use::stow(const std::string &s)
{
    return std::wstring(s.begin(), s.end());
}

const std::string Use::wtos(const std::wstring &ws)
{
    return std::string(ws.begin(), ws.end());
}

6
不要这样做,这会对包含非ASCII字符的字符串产生可怕的影响,并且很可能会生成无效的Unicode字符串。 - John Bandela

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接