在std::wstring和std::string之间处理UTF-8编码的字符串

3

我正在使用两个库,一个将UTF-8字符串存储在std::wstring中,另一个将字符串(UTF-8)存储在std::string中。
我可以使用什么最好 / 最有效的方法在这两个库之间传递字符串。
我目前正在使用Windows操作系统,使用Visual C++ v9 Express,但希望找到一个可移植的解决方案。


5
当你说“在std::wstring中存储UTF-8字符串”时,你指的确切是什么?你实际上是指UTF-16吗?std::wstring不适合存储UTF-8八位字节(但std::string适合)。 - Remy Lebeau
@Remy Lebeau 这是一个从数据库中检索UTF-8数据并以std::wstrings形式传递数据的ODBC库。 至于数据在库内的实际存储方式,我并不清楚。 - user754425
重要的是库如何将数据传递给/从您的代码中传递数据,而不是它如何在内部操作数据。如果它使用std::wstring,那么它很可能使用/期望UTF-16。这是有道理的,因为UTF-8和UTF-16只是相同Unicode字符集的不同编码。数据库可以使用除UTF-8之外的任何字符集,并且ODBC可能会在内部处理它并仍然使用UTF-16来传递数据以保持一致性。 - Remy Lebeau
如果您使用ODBC库检索ASCII范围之外的字符,例如à,那么wstring[0]的十进制或十六进制值是多少? - Mark Ransom
2个回答

5
假设您所说的是 std::wstring 使用的是 UTF-16 而不是 UTF-8,那么您需要将字符串从一个库编码/解码到另一个库。我不确定 STL 是否提供了这方面的功能,但是您可以使用 Windows 自带的 MultiByteToWideChar()WideCharToMultiByte() 函数仅使用几行代码就可以在 UTF-8 和 UTF-16 之间进行转换。然后,您可以将其封装到自己的函数中,以便在找到更具可移植性的逻辑时替换它,例如:
std::wstring Utf8ToUtf16(const std::string &s)
{
    std::wstring ret;
    int len = MultiByteToWideChar(CP_UTF8, 0, s.c_str(), s.length(), NULL, 0);
    if (len > 0)
    {
      ret.resize(len);
      MultiByteToWideChar(CP_UTF8, 0, s.c_str(), s.length(), const_cast<wchar_t*>(ret.c_str()), len);
    }
    return ret;
}

std::string Utf16ToUtf8(const std::wstring &s)
{
    std::string ret;
    int len = WideCharToMultiByte(CP_UTF8, 0, s.c_str(), s.length(), NULL, 0, NULL, NULL);
    if (len > 0)
    {
      ret.resize(len);
      WideCharToMultiByte(CP_UTF8, 0, s.c_str(), s.length(), const_cast<char*>(ret.c_str()), len, NULL, NULL);
    }
    return ret;
}

请注意,这是特定于Windows的内容,但UTF-16有望在此处表示Windows。 - rubenvb
无法编译,因为c_str返回一个const C字符串。但是因为走在正确的道路上而加1分。 - dalle
UTF-16并非仅限于Windows系统。唯一与Windows相关的部分是所使用的API函数。就像我所说的,这只是为了演示如何实现它。当原帖作者找到更具可移植性的解决方案时,他/她可以替换API函数而无需重写其余代码。 - Remy Lebeau
我现在添加了几个 const_cast 强制转换。 - Remy Lebeau
UTF-16 本身并非特定于 Windows,但假设 wchar_t 是 UTF-16 则是特定于 Windows 的。 - dan04

1
考虑使用ICU。它是可移植的,并且具有许多编码之间的转换器。

2
对于我的当前需求来说太大了。我的程序不到400KB,静态链接到运行时。ICU很可能会使其大小增加一倍以上,而我不确定是否可以静态链接它。 - user754425
如果不是 ICU,那就使用 iconv。这甚至符合 POSIX 标准。 - Kerrek SB

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