【问题标题】:C++ unicode questionsC++ unicode 问题
【发布时间】:2009-05-07 15:48:21
【问题描述】:

我知道 ICU 和代码项目中的 utf8 等小型库(忘记确切名称),但这些都不是我想要的。

我真正想要的是像重症监护室但以更友好的方式包裹起来的东西。

具体来说:

  • 完全面向对象
  • c++ 标准流的实现,或至少执行相同角色的东西。
  • 可以根据区域设置的方式格式化时间、日期等(例如,英国的 dd/mm/yy 和美国的 mm/dd/yy)。
  • 让我选择字符串的“内部”编码,例如,我可以让它在 windows 上使用 UTF-16,以避免在 windows API 和 DirectX 之间传递字符串时进行大量转换
  • 在编码之间轻松转换字符串

如果不存在这样的库,是否可以使用标准 c++ 类将 ICU 包装起来,因此我可以创建一个与 std::string 和 std::wstring 具有相同用法的 ustring,并实现版本的流(最好与现有的完全兼容,即我可以将它传递给一个期望 std::ostream 的函数,它将在其内部格式和 ascii(或 utf-8)之间进行转换) ?假设可能需要做多少工作?

编辑: 还查看了 c++0x 标准并注意到 utf8、utf16 和 utf32 的文字,这是否意味着标准库(例如字符串、流等)将完全支持这些编码以及它们之间的转换?如果是这样,有人知道 Visual Studio 支持这些功能需要多长时间?

编辑2: 至于使用现有的 c++ 支持,我会查找 locale 和 facet 的东西。

我遇到的一个问题是,当使用围绕 wchar_t 定义的流时,它在 windows 下是 2 个字节的文件 i/o 但是它似乎仍然对它们自己的文件使用 ascii。

std::wofstream file(L"myfile.txt", std::ios::out);
file << L"Hello World!" << std::endl;

导致文件中出现以下十六进制
48 65 6C 6C 6F 20 57 6F 72 6C 64 0D 0A
这显然是 ascii 而不是预期的 utf-16 输出:
FF FE 48 00 65 00 6C 00 6C 00 6F 00 20 00 57 00 6F 00 72 00 6C 00 64 00 0D 00 0A 00

【问题讨论】:

  • UTF-16 文本实际上已转换为本地 8 位编码!因此,您不要将 utf-16 写入文件。不要忘记调用 std::locale::global(std::locale());
  • 好的,那么我如何告诉它我想要文件的编码是什么?我尝试了你上面提到的 std::local... 但它似乎没有任何效果:(
  • 好的,例如,如果系统语言环境ru_RU.UTF-8,那么编码是utf-8,如果是ru_RU.KOI-8,那么它就是KOI。您还可以指定其他语言环境:locale::globale(locale("de_DE.ISO-8859-1"));(注意,我使用 POSIX 名称语言环境名称,对于 Windows,您应该检查语言环境名称是什么
  • 好的,那么我如何获取当前语言环境(en_Us、en_Uk 等)并将其设置为 utf-16 用于宽文件 io(以及 assci/utf-8 用于窄流)

标签: c++ unicode wofstream


【解决方案1】:

我真正想要的是像重症监护室但以更友好的方式包裹起来的东西

不幸的是,没有这样的事情。他们的 API 并没有那么糟糕,所以你可以通过一些努力来适应它。

可以根据语言环境设置时间、日期等格式(例如,英国的 dd/mm/yy 和美国的 mm/dd/yy)。

std::locale 类中完全支持它,请阅读如何使用它。您还可以为 std::iostream 指定区域设置,以便正确格式化数字、日期。

在编码之间轻松转换字符串

std::locale 提供了用于将 8 位本地编码转换为宽一并返回的方面。

所以我可以让它使用 UTF-16

ICU 内部使用 utf-16,win32 wchar_t 和 wstring 也使用 utf-16,在其他操作系统下,大多数实现将 wchar_t 作为 utf-32,wstring 使用 utf-32。

备注:std::locale的支持并不完美,但它已经提供了许多对字符操作有用的工具。

见:http://www.cplusplus.com/reference/std/locale/

【讨论】:

    【解决方案2】:

    这就是我使用 ICU 在 std::string(UTF-8 格式)和 std::wstring 之间进行转换的方式

    /** Converts a std::wstring into a std::string with UTF-8 encoding.
     */
    template < typename StringT >
    StringT utf8 ( std::wstring const & rc_string );
    
    /** Converts a std::String with UTF-8 encoding into a std::wstring.
     */
    template < typename StringT >
    StringT utf8 ( std::string const & rc_string );
    
    /** Nop specialization for std::string.
     */
    template < >
    inline std::string utf8 ( std::string const & rc_string )
    {
      return rc_string;
    }
    
    /** Nop specialization for std::wstring.
     */
    template < >
    inline std::wstring utf8 ( std::wstring const & rc_string )
    {
      return rc_string;
    }
    
    template < >
    std::string utf8 ( std::wstring const & rc_string )
    {
      std::string result;
      if(rc_string.empty())
        return result;
    
      std::vector<UChar> buffer;
    
      result.resize(rc_string.size() * 3); // UTF-8 uses max 3 bytes per char
      buffer.resize(rc_string.size() * 2); // UTF-16 uses max 2 bytes per char
    
      UErrorCode status = U_ZERO_ERROR;
      int32_t len = 0;
    
      u_strFromWCS(
        &buffer[0],
        buffer.size(),
        &len,
        &rc_string[0],
        rc_string.size(),
        &status
      );
      if(!U_SUCCESS(status))
      {
        throw XXXException("utf8: u_strFromWCS failed");
      }
      buffer.resize(len);
    
      u_strToUTF8(
        &result[0],
        result.size(),
        &len,
        &buffer[0],
        buffer.size(),
        &status
      );
      if(!U_SUCCESS(status))
      {
        throw XXXException("utf8: u_strToUTF8 failed");
      }
      result.resize(len);
    
      return result;
    }/* end of utf8 ( ) */
    
    
    template < >
    std::wstring utf8 ( std::string const & rc_string )
    {
      std::wstring result;
      if(rc_string.empty())
        return result;
    
      std::vector<UChar> buffer;
    
      result.resize(rc_string.size());
      buffer.resize(rc_string.size());
    
      UErrorCode status = U_ZERO_ERROR;
      int32_t len = 0;
    
      u_strFromUTF8(
        &buffer[0],
        buffer.size(),
        &len,
        &rc_string[0],
        rc_string.size(),
        &status
      );
      if(!U_SUCCESS(status))
      {
        throw XXXException("utf8: u_strFromUTF8 failed");
      }
      buffer.resize(len);
    
      u_strToWCS(
        &result[0],
        result.size(),
        &len,
        &buffer[0],
        buffer.size(),
        &status
      );
      if(!U_SUCCESS(status))
      {
        throw XXXException("utf8: u_strToWCS failed");
      }
      result.resize(len);
    
      return result;
    }/* end of utf8 ( ) */
    

    使用就是这么简单:

    std::string s = utf8<std::string>(std::wstring(L"some string"));
    std::wstring s = utf8<std::wstring>(std::string("some string"));
    

    【讨论】:

    • 一个错误:UTF-8 每个字符最多使用 4 个字节。术语的一种错误用法:UTF-16 每个字符最多使用 2 个代码单元
    【解决方案3】:

    我总是这样工作:

    某种编码的字节流 -> ICU -> wistream -> stl & boost -> wostream -> ICU -> 某种编码的字节流

    【讨论】:

      【解决方案4】:

      可以通过指定特定的语言环境来格式化日期、时间等。至于你自己的滚动——总是有可能的,你可以从底层库中获取尽可能多的资源。

      还查看了 c++0x 标准并注意到 utf8、utf16 和 utf32 的文字,这是否意味着标准库(例如字符串、流等)将完全支持这些编码以及它们之间的转换?

      是的。但请注意,这些是不同的数据类型,而不是您的常规 wchar 序列或 wstring

      如果有的话,有人知道 Visual Studio 支持这些功能需要多长时间?

      据我所知:vc9 (VS2008) 仅部分支持某些 TR1 功能。 vc10(VS2010)预计会有更好的支持。

      【讨论】:

      • 是的,但它不会将其格式化为某种编码,当然我可以将其格式化为 ascii 字符串然后对其进行编码,但是如果我想在中文中使用长月份名称,这是不可能的ascii?
      • 这就是语言环境的编码部分发挥作用的地方。另外,查找方面。
      • 是的。未充分利用的是本地功能。不要对您的用户强制使用格式。让系统决定格式,您所要做的就是确保正确设置区域设置,然后流将正常工作。 (+1)
      • “但请注意,这些是不同的数据类型,而不是常规的 wchar 序列或 wstring。”因此,当我创建一个具有重载 >> 和
      • 不,对于 C++0x,您将使用这些新类型,而不是 wchar_t 或 wstring。
      【解决方案5】:

      我做了自己的小包装。如果你愿意,我可以分享。

      【讨论】:

      • 它是否支持 c++ 流,因为我在 ICU 的主要问题以及我有一个非常大的应用程序想要使用 unicode 的事实。
      【解决方案6】:

      运气不好。我知道 Dinkumware 库提供了一些 Unicode 支持——你可以查看他们网站上的文档。 AFAIK,它不是免费的。

      【讨论】:

        猜你喜欢
        • 2013-02-12
        • 1970-01-01
        • 2013-12-18
        • 2011-07-26
        • 2014-02-17
        • 2010-12-26
        • 2011-11-09
        • 2010-12-16
        • 2023-03-08
        相关资源
        最近更新 更多