【问题标题】:Compare unicode std::string with usual "" literal or u8"" declartion将 unicode std::string 与通常的 "" literal or u8"" 声明进行比较
【发布时间】:2017-05-01 07:08:18
【问题描述】:

在装有 Visual Studio 2015 的 Windows 上

    // Ü
    //    UTF-8  (hex) 0xC3 0x9C 
    //    UTF-16 (hex) 0x00DC 
    //    UTF-32 (hex) 0x000000DC 

    using namespace std::string_literals;
    const auto narrow_multibyte_string_s = "\u00dc"s;
    const auto wide_string_s             = L"\u00dc"s;
    const auto utf8_encoded_string_s     = u8"\u00dc"s;
    const auto utf16_encoded_string_s    = u"\u00dc"s;
    const auto utf32_encoded_string_s    = U"\u00dc"s;

    assert(utf8_encoded_string_s     == "\xC3\x9C");
    assert(narrow_multibyte_string_s ==        "Ü");
    assert(utf8_encoded_string_s     ==      u8"Ü");

    // here is the question
    assert(utf8_encoded_string_s != narrow_multibyte_string_s);

"\u00dc"su8"\u00dc"s 不同或 "Ü"su8"Ü"s

显然,通常字符串文字的默认编码不是 UTF-8(可能是 UTF-16),即使它们具有相同的语义,我也不能在不知道其编码的情况下比较两个 std::string。

在启用 unicode 的 c++ 应用程序开发中执行这种字符串比较的做法是什么??

例如这样的 API:

  class MyDatabase
  {
      bool isAvailable(const std::string& key)
      {
         // *compare*  key in database
         if (key == "Ü")
           return true;
         else
           return false;
      }
  }

其他程序可能使用 UTF-8 或默认(UTF-16?)编码的 std::string 调用 isAvailable。我怎样才能保证进行适当的比较?

我可以在编译时检测到任何编码不匹配吗?

注意:我更喜欢 C++11/14 的东西。 比 std::wstring 更喜欢 std::string

【问题讨论】:

  • UTF-16 仅与wstring 一起使用,在您的问题中每次提到它绝对是一个错误的猜测。默认编码可能是编译时的当前 ANSI 代码页。或者更准确地说,默认是不重新编码,保留源文件的编码,出于语法处理的目的,编译器假定为ANSI。

标签: c++11 unicode utf-8 stdstring string-literals


【解决方案1】:

"\u00dc" 是一个 char[] 编码,无论编译器/操作系统的默认 8 位编码恰好是什么,所以它在不同的机器上可能会有所不同。在 Windows 上,这往往是操作系统的默认 Ansi 编码,也可能是源文件保存为的编码。

L"\u00dc" 是使用 UTF-16 或 UTF-32 编码的 wchar_t[],具体取决于编译器对 wchar_t 的定义(在 Windows 上是 16 位,因此是 UTF-16)。

u8"\u00dc" 是一个以 UTF-8 编码的char[]

u"\u00dc" 是一个以 UTF-16 编码的char16_t[]

U"\u00dc" 是一个以 UTF-32 编码的char32_t[]

""s 后缀仅返回 std::stringstd::wstringstd::u16stringstd::u32string,具体取决于是否传递了 char[]wchar_t[]char16_t[]char32_t[]给它。

比较两个字符串时,首先要确保它们的编码相同。这对于您的char[]/std::string 数据尤其重要,因为它可以采用任意数量的 8 位编码,具体取决于所涉及的系统。如果应用程序自己生成字符串,这不是什么大问题,但如果一个或多个字符串来自外部源(文件、用户输入、网络协议等),这一点很重要。

在您的示例中,"\u00dc""Ü" 不一定保证产生相同的 char[] 序列,具体取决于编译器如何解释这些不同的文字。但即使他们这样做了(在您的示例中似乎就是这种情况),他们都不会产生 UTF-8(您必须采取额外措施来强制执行),这就是您与 utf8_encoded_string_s 的比较失败的原因。

因此,如果您希望字符串文字为 UTF-8,请使用 u8"" 来确保这一点。如果您从外部源获取字符串数据并且需要它是 UTF-8 格式,请尽快将其转换为 UTF-8 代码,如果还没有的话(这意味着您必须知道外部来源)。

【讨论】:

  • L"\u00dc" 以“支持的语言环境中指定的最大扩展字符集”[basic.fundamental] 编码,不保证为 UTF-16/32(例如,它可能随 @ 987654349@).
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-28
相关资源
最近更新 更多