将unicode std :: string与通常的“”文字或u8“”声明进行比较

时间:2016-12-15 15:54:34

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

在使用Visual Studio 2015的Windows上

parse = icBuilder.parse(new InputSource(new StringReader(xmlString)));

“\ u00dc” u8“\ u00dc”“Ü”不一样的 U8的 “u”

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

在unicode-enable c ++应用程序开发中执行此类字符串比较的做法是什么?

例如这样的API:

    // Ü
    //    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);

其他程序可以使用UTF-8中的std :: string或默认(UTF-16?)编码来调用isAvailable。我怎么能保证做正确的比较?

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

注意:我更喜欢C ++ 11/14。       首选std :: string而不是std :: wstring

1 个答案:

答案 0 :(得分:2)

无论编译器/操作系统的默认8位编码是什么,

"\u00dc"都是char[]编码的,因此在不同的机器上可能会有所不同。在Windows上,这往往是操作系统的默认Ansi编码,或者它可能是源文件保存为的编码。

L"\u00dc"是一个wchar_t[],编码为UTF-16或UTF-32,具体取决于编译器对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[],{{ 1}},wchar_t[]char16_t[]传递给它。

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

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

因此,如果您希望字符串文字为UTF-8,请使用utf8_encoded_string_s来确保。如果您从外部源获取字符串数据并且需要它是UTF-8,请尽快将其转换为代码中的UTF-8(如果尚未使用)(这意味着您必须知道所使用的编码)外部来源)。