C++读写UTF-32文件

C++ read and write UTF-32 files

我想使用 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

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

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

所以我的问题是:如何 write/open UTF-32 格式的文件?如果不需要第三方库,我更愿意,除非它们是 Windows 的一部分或者通常随 OS.

一起提供

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

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

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

典型的解决方案是使用"byte order mark" 作为文件的第一个字符。 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);
}

I am currently interested in is another European language, [so] ASCII might suffice

没有。即使是简单的英语。您知道 Microsoft Word 如何创建“弯引号”吗?这些是非 ASCII 字符。例如,所有带有重音符号和变音符号的字母。法语或英语是非 ASCII 字符。

I want to future-proof it

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

也为了未来的证明:我很确定一些脚本使用由多个代码点组成的字符(技术术语是“字素簇”)。粗略搜索出现 Playing around with Devanagari characters.

UTF-32 的一个缺点是其他工具的支持。记事本不会打开您的文件。 Beyond Compare 不会。 Visual Studio 代码……不。 Visual Studio 会,但它不会让您创建此类文件。

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

所以我对这个问题的诚实回答是,不要。否则按照 Nicol 的回答。