【问题标题】:How to convert Unicode string into a utf-8 or utf-16 string?如何将 Unicode 字符串转换为 utf-8 或 utf-16 字符串?
【发布时间】:2010-09-21 18:36:18
【问题描述】:

如何将 Unicode 字符串转换为 utf-8 或 utf-16 字符串? 我的 VS2005 项目使用的是 Unicode 字符集,而 cpp 中的 sqlite 提供

int sqlite3_open(
  const char *filename,   /* Database filename (UTF-8) */
  sqlite3 **ppDb          /* OUT: SQLite db handle */
);
int sqlite3_open16(
  const void *filename,   /* Database filename (UTF-16) */
  sqlite3 **ppDb          /* OUT: SQLite db handle */
);

用于打开文件夹。 如何将字符串、CString 或 wstring 转换为 UTF-8 或 UTF-16 字符集?

非常感谢!

【问题讨论】:

    标签: c++ unicode utf-8 character-encoding utf-16


    【解决方案1】:

    简答:

    如果您使用 Unicode 字符串,例如 CString 或 wstring,则无需转换。使用 sqlite3_open16()。 您必须确保传递一个 WCHAR 指针(转换为 void *。似乎很蹩脚!即使这个库是跨平台的,我想他们也可以定义一个取决于平台的宽字符类型,并且比不友好void *) 到 API。比如对于一个CString:(void*)(LPCWSTR)strFilename

    更长的答案:

    您没有要转换为 UTF8 或 UTF16 的 Unicode 字符串。您的程序中有一个使用给定编码表示的 Unicode 字符串:Unicode 本身不是二进制表示。编码说明 Unicode 代码点(数值)在内存中的表示方式(数字的二进制布局)。 UTF8 和 UTF16 是使用最广泛的编码。但它们非常不同。

    当一个 VS 项目说“Unicode charset”时,它实际上意味着“字符被编码为 UTF16”。因此,您可以直接使用 sqlite3_open16()。无需转换。字符存储在 WCHAR 类型(与 char 相对)中,它占用 16 位(标准 C 类型 wchar_t 的回退,在 Win32 上占用 16 位。在其他平台上可能会有所不同。感谢您的更正,Checkers)。

    您可能还需要注意一个细节:UTF16 有 2 种风格:Big Endian 和 Little Endian。这就是这 16 位的字节顺序。您为 UTF16 提供的函数原型没有说明使用哪种排序。但是假设 sqlite 使用与 Windows 相同的字节序(Little Endian IIRC。我知道顺序但总是对名称有问题:-)),那么你就很安全了。

    编辑:对跳棋评论的回答:

    UTF16 使用 16 位 代码单元。在 Win32 下(在 Win32 上),wchar_t 用于此类存储单元。诀窍是一些 Unicode 字符需要 2 个这样的 16 位代码单元的序列。它们被称为代理对。

    UTF8 使用 1 到 4 字节序列表示 1 个字符的方式相同。然而 UTF8 与 char 类型一起使用。

    【讨论】:

    • 不,不,不! sqlite3_open16() 使用 'void*' 参数,因为它被声明为 UTF16,NOT wchar_t,它在不同平台上大小不同,可能是也可能不是 UTF16(即 glibc 有 4 字节wchar_t).
    • 跳棋:在上面看到我的回答编辑
    • 是的,我知道 UTF16 表示。但是,您不能假设 wchar_t 的内部表示在所有平台上都是相同的,事实并非如此。
    • "引入 wchar_t 的 ISO C90 标准并没有具体说明表示。它只要求该类型能够存储基本字符集的所有元素"gnu.org/software/libtool/manual/libc/Extended-Char-Intro.html
    • 实际上,我会说 UTF16 使用 16 位代码(不是字符),就像 UTF8 使用 8 位(八位字节)代码一样。 Unicode 字符代码(最多 20 位)对于常用字符需要 1 个 UTF16 代码,但对于其他字符需要两个(称为代理对)。
    【解决方案2】:

    使用WideCharToMultiByte 函数。为CodePage 参数指定CP_UTF8

    CHAR buf[256]; // or whatever
    WideCharToMultiByte(
      CP_UTF8, 
      0, 
      StringToConvert, // the string you have
      -1, // length of the string - set -1 to indicate it is null terminated
      buf, // output
      __countof(buf), // size of the buffer in bytes - if you leave it zero the return value is the length required for the output buffer
      NULL,    
      NULL
    );
    

    此外,Windows 中 unicode 应用程序的默认编码是 UTF-16LE,因此您可能不需要执行任何翻译,只需使用第二个版本 sqlite3_open16

    【讨论】:

    • 我不推荐固定缓冲区;相反,使用动态分配的缓冲区(例如,std::vector),根据需要扩展(当 WideCharToMultiByte 告诉你你的字符串太小时)。
    • 我不同意:您展示了如何从 UTF16 转换为 UTF8。这不是 OP 的要求,因为似乎有一个可用于宽字符字符串的函数:sqlite3_open16()。 IMO,正确答案是:使用 sqlite3_open16()。
    • @Chris 这就是为什么我说“或其他”并将评论放在输出缓冲区大小上 - 我不想让事情复杂化太多
    【解决方案3】:

    所有 C++ 字符串类型都是字符集中性的。他们只是确定一个字符宽度,而不做进一步的假设。 wstring 在 Windows 中使用 16 位字符,大致对应于 utf-16,但它仍然取决于您在线程中存储的内容。 wstring 不会以任何方式强制您放入其中的数据必须是有效的 utf16。 Windows 在定义 UNICODE 时使用 utf16,因此您的字符串很可能已经是 utf16,您无需执行任何操作。

    其他一些人建议使用 WideCharToMultiByte 函数,这是将 utf16 转换为 utf8 的方法之一。但既然 sqlite 可以处理 utf16,那应该是没有必要的。

    【讨论】:

      【解决方案4】:

      utf-8 和 utf-16 都是“unicode”字符编码。您可能谈论的是 utf-32,它是一种固定大小的字符编码。也许正在寻找

      "Convert utf-32 into utf-8 or utf-16"

      在这方面为您提供一些结果或其他论文。

      【讨论】:

        【解决方案5】:

        最简单的方法是使用 CStringA。 CString 类是 CStringA(ASCII 版本)或 CStringW(宽字符版本)的 typedef。这两个类都有构造函数来转换字符串类型。我通常使用:

        sqlite3_open(CStringA(L"MyWideCharFileName"), ...);
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-02-05
          • 2012-07-02
          • 1970-01-01
          • 2011-09-06
          • 2012-02-22
          • 1970-01-01
          • 2021-07-06
          • 1970-01-01
          相关资源
          最近更新 更多