C++读取和写入 UTF-32 文件

C++ read and write UTF-32 files

本文关键字:UTF-32 文件 读取 C++      更新时间:2023-10-16

我想使用Visual Studio 2017,C++和WindowsAPI(以前称为Win32(为自己编写一个语言学习应用程序。操作系统是最新的Windows 10内部版本,向后兼容性不是问题。由于我假设英语是用户的母语,而我目前感兴趣的语言是另一种欧洲语言,因此ASCII可能就足够了。但是我想让它面向未来(更多的语言(,我也想尝试使用 UTF-32。我以前使用过 UTF-8 和 UTF-16,尽管我对后者有更多的经验。

多亏了std::basic_string,很容易弄清楚如何获得UTF-32字符串:

typedef std::basic_string<char32_t> stringUTF32

由于我为所有 GUI 员工使用 WinAPI,因此我需要在 UTF-32 和 UTF-16 之间进行一些转换。

现在谈谈我的问题:由于 UTF-32 因其效率低下而未被广泛使用,因此网络上几乎没有任何关于它的材料。为了避免不必要的转换,我想将我的词汇表和其他数据保存为 UTF-32(对于所有 UTF-8 倡导者/布道者,替代方案是 UTF-16(。问题是,我找不到如何用 UTF-32 编写和打开文件。

所以我的问题是:如何用 UTF-32 编写/打开文件?如果不需要第三方库,我宁愿,除非它们是 Windows 的一部分或通常随该操作系统一起提供。

如果你有一个char32_t序列,你可以使用std::basic_ofstream<char32_t>将其写入文件(我称之为u32_ofstream,但这个typedef不存在(。这和std::ofstream完全一样,只是它写的是char32_ts而不是chars。但也有局限性。

大多数具有operator<<重载的标准库类型都是在字符类型上模板化的。所以他们会和u32_ofstream一起工作得很好。您将遇到的问题是用户类型。这些几乎总是假设你正在写char,因此被定义为ostream &operator<<(ostream &os, ...);。此类流输出无法与没有转换层的u32_ofstream一起使用。

但是你将要面对的大问题是字节序问题。u32_ofstreamchar32_t编写为平台的本机字节序。如果您的应用程序通过u32_ifstream读回它们,那很好。但是,如果其他应用程序读取它们,或者您的应用程序需要读取其他人用 UTF-32 编写的内容,这将成为一个问题。

典型的解决方案是使用"字节顺序标记"作为文件的第一个字符。Unicode 甚至为此预留了一个特定的代码点:U0000FEFF

BOM 的工作方式是这样的。写入文件时,先于任何其他代码点编写 BOM。

读取未知编码的文件时,您可以正常读取第一个代码点。如果它等于本机编码中的 BOM,那么您可以正常读取文件的其余部分。如果没有,则需要先读取文件并对其进行字节序转换,然后才能对其进行处理。该过程看起来有点像这样:

constexpr char32_t native_bom = U'U0000FEFF';
u32_ifstream is(...);
char32_t bom;
is >> bom;
if(native_bom == bom)
{
process_stream(is);
}
else
{
basic_stringstream<char32_t> char_stream
//Load the rest of `is` and endian-convert it into `char_stream`.
process_stream(char_stream);
}

我目前感兴趣的是另一种欧洲语言,[所以] ASCII 可能就足够了

不。即使是简单的英语。你知道Microsoft Word 是如何创建"卷曲引号"的吗?这些是非 ASCII 字符。所有那些带有重音和变音符号的字母,例如。法语或英语是非 ASCII 字符。

我想让它面向未来

UTF-8、UTF-16 和 UTF-32 都可以对每个 Unicode 码位进行编码。它们都是面向未来的。UTF-32 与其他两个相比没有优势。

同样为了将来证明:我很确定某些脚本使用由多个代码点组成的字符(技术术语是"字素簇"(。粗略搜索一下,就会发现"玩弄梵文"字符。

UTF-32 的一个缺点是支持其他工具。记事本无法打开您的文件。超越比较不会。Visual Studio Code...不。Visual Studio会,但它不会让你创建这样的文件。

还有Win32 API:它有一个函数MultiByteToWideChar,可以将UTF-8转换为UTF-16(你需要传递给所有Win32调用(,但它不接受UTF-32。

所以我对这个问题的诚实回答是,不要。否则,请遵循尼科尔的回答。