【问题标题】:Basic issue regarding full unicode in C++关于 C++ 中完整 unicode 的基本问题
【发布时间】:2018-01-30 05:56:27
【问题描述】:

在 C++ 中用于完整 unicode 的正确工具是什么?

例如,我试过:

int main()                                                                                                                                                                 
{                                                                                                                                                                          
    std::wstring name;                                                                                                                                                 
    std::wcout << "Enter unicode: " << std::endl;                                                                                                                
    std::getline(std::wcin, name);                                                                                                                                     

    std::wcout << name << std::endl;                                                                                                                                   

    return 0;                                                                                                                                                              
}  

当输入字符时,它并没有像我预期的那样工作:????或其他不在 Unicode BMP 中的内容。我得到一个空行打印出来。

纯字符串适用于最高 16 位的任何代码点,wstring、wcin、wcout 无法按我的预期工作,并且一些谷歌搜索并没有帮助我了解这可能是什么错误。

编辑(文件 I/O 也有问题!):

我想知道这是否与控制台 I/O 本身有关,并想尝试对文件 I/O 进行相同的实验。我查看了 api 并想出了编译和运行良好的这个:

int main()                                                                                                                                                                 
{                                                                                                                                                                          
    std::string filename;                                                                                                                                                  
    std::cout << "Enter file to append to: " << std::endl;                                                                                                                 
    std::getline(std::cin, filename);                                                                                                                                      

    std::wifstream file;                                                                                                                                                   
    std::wstringstream buff;                                                                                                                                               
    file.open(filename);                                                                                                                                                   
    std::wstring txt;                                                                                                                                                      
    buff << file.rdbuf();                                                                                                                                                  
    file.close();                                                                                                                                                          
    txt = buff.str();                                                                                                                                                      

    std::wcout << txt << std::endl;                                                                                                                                        

    return 0;                                                                                                                                                              
}                                                                                                                                                                          

但是当我将它指向我的文件时,它主要包含 lorem ipsum 和一些非 BMP 字符,它会将文件打印到第一个非 BMP 字符,然后提前停止。现代 C++ 中的 Unicode 设施真的可以这么糟糕吗?

我确定有人知道我在这里缺少的一些基本知识...

【问题讨论】:

  • 谢谢老爷。我在 debian 上寻找平台中立的解决方案,纯 C++ 解决方案。此链接似乎提供了一个非常特定于 Windows 的答案。
  • 您应该为 Unicode 字符串文字使用 L 前缀:std::wcout
  • 好的,好的提示。在这种情况下不会影响我的错误。
  • 它确实最终取决于输出流。例如,默认情况下,Windows 不支持标准控制台中的完整 unicode 字符集。 stackoverflow.com/questions/388490/… 所以你必须添加一些平台相关的调整。

标签: c++ unicode wstring


【解决方案1】:

您处于 C++ unicode 的灰色地带。 Unicode 最初是由 7 位 ASCII 字符或多字节字符扩展为纯 16 位字符开始的,后来成为 BMP。这些 16 位字符被 Java 等语言和 Windows 等系统原生采用。 C 和 C++ 在标准观点上更加保守,决定 wchar_t 将是一个 实现相关 宽字符集,可以是 16 位或 32 位宽(甚至更多...),具体取决于要求。好的一面是它是可扩展的,不好的一面是当 wchar_t 仅为 16 位时,如何表示非 BMP unicode 字符从未明确。

然后创建

UTF-16 以允许这些非 BMP 字符的 标准 表示,缺点是它们需要 2 个 16 位字符,如果某些字符,std::char_traits&lt;wchar_t&gt;::length 将再次出错它们中的一部分存在于 wstring 中。

这就是为什么大多数 C++ 实现选择 wchar_tbasic IO 只会正确处理 length 的 BMP unicode 字符以返回真实数量的字符。

当需要完整的 unicode 支持时,C++ 风格的方法是使用基于 char32_t 的字符串。事实上,wstring_twchar_t(前缀 L 表示 litteral)是依赖于实现的类型,并且从 C++11 开始,您还拥有明确使用 UTF-16 的 char16_tu16string(前缀 u),或 @ 987654330@ 和 u32string(前缀 U)通过 UTF-32 获得完整的 unicode 支持。将 BMP 之外的字符存储在 u16 字符串中的问题在于,您丢失了 字符串大小 == 字符数 属性,这是使用宽字符而不是多字节字符的关键原因。

u32string 的一个问题是 io 库仍然没有直接专门化 32 位字符,但正如转换器所具有的那样,当您处理带有 std::basic_fstream&lt;char32_t&gt; 的文件时,您可能可以轻松使用它们(未经测试,但根据标准应该工作)。但是您将没有cincoutcerr 的标准流,并且可能必须处理来自stringu16stringnative,然后将所有内容转换为u32string 在 C++14 中引入的标准转换器的帮助下,或者如果只使用 C++11 则很难。

真正的阴暗面是,由于本机部分目前依赖于操作系统,您将无法设置一种完全可移植的方式来处理完整的 unicode - 或者至少我不知道。

【讨论】:

  • std::u16string 不限于 BMP(std::string 是在使用 UTF-8 时,或者std::wstring 是在使用 UTF-16/32 时,取决于 @ 的大小987654342@)。 char16_tstd::u16string 是专门为 UTF-16 设计的(u"" 字符串前缀返回一个完整的 UTF-16 编码的std::u16string,而不是像你暗示的那样是一个 UCS-2 编码的)。 UTF-16 处理整个 Unicode 曲目。 char32_tstd::u32string 是为 UTF-32 设计的,它也处理整个 Unicode 曲目。
  • @RemyLebeau:感谢您的评论!我的意思是,当您在 u16string 中使用 UTF-16 编码的字符串时,您会丢失正确的 length == number of chars,这是使用宽字符而不是多字节字符的关键原因。希望现在更清楚了
  • length == number of chars 属性在几十年前随着 MBCS 字符集的发明而丢失。只有专门处理英语和其他拉丁语言的代码才能依赖该属性。真正的国际应用程序不会长时间使用该属性。话虽如此,大多数现代语言都适合 BMP,因此属性通常在大多数文本中都成立。亚洲语言,以及最近的表情符号,以及 Unicode 的不太常见的用法(古代语言、数学/音乐符号等),都需要使用代理。
猜你喜欢
  • 2021-10-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-30
  • 2013-10-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多