关于C++中完整 unicode 的基本问题

Basic issue regarding full unicode in C++

本文关键字:问题 unicode C++ 关于      更新时间:2023-10-16

在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设施真的可以这么糟糕吗?

我敢肯定有人知道我在这里缺少的一些基本的东西......

你处于 unicode C++灰色地带。Unicode 最初是由 7 位 ASCII 字符或多字节字符扩展到纯 16 位字符开始的,后来成为 BMP。这16位字符被Java等语言和Windows等系统原生采用。C 和 C++ 在标准观点上更加保守,决定wchar_t将是一个依赖于实现的宽字符集,根据需求,可以是 16 或 32 位宽(甚至更多......好的一面是它是可扩展的,黑暗的一面是,当wchar_t只有 16 位时,从未明确说明应该如何表示非 BMP unicode 字符。

然后创建 UTF-16 以允许这些非 BMP 字符的标准表示,缺点是它们需要 2 个 16 位字符,并且如果其中一些字符存在于 wstring 中,则std::char_traits<wchar_t>::length将再次出错。

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

C++式的方法是在需要完全 unicode 支持时使用基于char32_t的字符串。事实上,wstring_twchar_t(前缀 L 表示 litteral(是依赖于实现的类型,从 C++11 开始,您还有显式使用 UTF-16 的char16_tu16string(前缀 u(,或者通过 UTF-32 提供完全 unicode 支持的char32_tu32string(前缀 U(。在 u16string 中存储 BMP 外部字符的问题在于,您丢失了字符串 == 字符数的属性大小,这是使用宽字符而不是多字节字符的关键原因。

u32string 的一个问题是 io 库仍然没有针对 32 位字符的直接专用化,但正如转换器一样,当您使用std::basic_fstream<char32_t>处理文件时,您可能可以轻松使用它们(未经测试但根据标准应该工作(。但是您将没有用于cincoutcerr的标准流,并且可能必须从stringu16string中处理本机,然后在 C++14 中引入的标准转换器的帮助下转换u32string中的所有内容,或者如果仅使用 C++11,则很难。

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