在Windows中执行UTF-8

介绍 这是(又是一篇)关于如何在一个仍然鼓励UTF-16编码的平台上处理UTF-8编码的文章。为此,我也提供了一个小型图书馆。代码工作,它是干净的,容易理解和小。 这是UTF-8 Everywhere宣言中提倡的解决方案的实现。我强烈建议您将整个文档阅读一遍,以便给商标灌输思想。 背景 让我重述一下上述宣言中的一些要点: UTF-16(被称为Unicode、widechar或UCS-2)早在90年代初就被引入了,当时人们认为它的65000个字符对于所有字符来说已经足够了,除了特殊情况,UTF-16并没有比UTF-8更有效或更容易使用。事实上,在很多情况下,情况正好相反。在UTF-16中,字符也有可变宽度编码(两个或四个字节),计数字符和UTF-8中一样困难。 如果你想在Windows中使用UTF-8编码(你应该这么做),并且你不想变得疯狂或者你的程序意外崩溃,你必须遵循以下规则: 在编译程序时定义_UNICODE(或在Visual Studio中选择“使用Unicode字符集”)。只在API函数调用的参数中使用wchar_t或std::wstring。在其他地方使用char或std::string。在UTF-8和UTF-16之间使用加宽()和窄()函数。 这个包中提供的函数将使您的工作更加轻松。 调用库函数 所有函数都存在于utf8名称空间中,我建议您不要为这个名称空间放置using指令。这是因为许多/大多数函数具有与传统C函数相同的名称。例如,如果你有一个函数调用:

mkdir (folder_name);

如果你想开始使用UTF-8字符,你只需要把它改为:

utf8::mkdir (folder_name);

将名称空间作为函数的前缀可以使您明显地看到所使用的函数。 基本的转换功能 遵循同样的原则,基本的转换函数是narrow()(从UTF-16转换为UTF-8)和broaden()(反向转换)。他们的签名是:

std::string narrow (const wchar_t* s);
std::string narrow (const std::wstring& s);

std::wstring widen (const char* s);
std::wstring widen (const std::string& s);

此外,还有两个转换UTF-32的函数:

std::string narrow (const std::u32string& s);
std::u32string runes (const std::string& s);

在内部,转换是使用WideCharToMultiByte和MultiByteToWideChar函数完成的。 还有一些函数用于计数UTF-8字符串中的字符数(length()),检查字符串是否有效(valid()),以及在字符串中推进指针/迭代器(next())。 包装器 几乎所有其他函数都是传统C/ c++函数或结构的包装器: 文件操作:fopen, chmod, access, rename, remove streams: ifstream, ofstream, fstream路径操作函数:splitpath和makepath环境访问函数putenv和getenv字符分类函数是…(isalnum, isdigit, isalpha等) 所有这些函数的参数都模仿标准参数。但是,对于其中一些,如access、rename等,返回类型为bool, true表示成功,false表示失败。这与标准的C函数相反,如果成功,则返回0。购者自慎! 返回值 对于返回字符串的API函数,您需要设置一个wchar_t缓冲区来接收值,使用这个窄函数将其转换为UTF-8,并最终释放缓冲区。下面是一个示例。代码检索临时文件的名称:

wstring wpath (_MAX_PATH, L'\0');
wstring wfname (_MAX_PATH, L'\0');

GetTempPath (wpath.size (), const_cast<wchar_t*>(wpath.data ()));
GetTempFileName (wpath.c_str(), L"ABC", 1, const_cast<wchar_t*>(wfname.data ()));

string result = narrow(wfname);

这似乎有点太麻烦和容易出错,所以我做了一个小对象,以保存返回值。它有运算符将其转换为wchar_t缓冲区,然后转换为UTF-8字符串。由于没有更好的名称,我称它为缓冲区。使用这个对象,相同的代码片段变成:

utf8::buffer path (_MAX_PATH);
utf8::buffer fname (_MAX_PATH);

GetTempPath (path.size (), path);
GetTempFileName (path, L"ABC", 1, fname);

string result = fname;

在内部,缓冲区对象包含UTF-16字符,但是字符串转换操作符调用utf8::narrow函数将字符串转换为UTF-8。 程序参数 有两个函数用于访问和转换UTF-16编码的程序参数:get_argv函数返回一个类似argv的指针数组,指向命令行参数:

  int argc;
 char **argv = utf8::get_argv (&argc);

第二个直接提供了字符串的向量:

std::vector<std::string> argv = utf8::argv ();

当使用第一个函数时,必须调用utf8::free_argv函数来释放为argv数组分配的内存。 结论 我希望这篇文章和包含的代码能够说明在Windows程序中使用UTF-8编码并不会太痛苦。 本系列的下一章是: “降低还是不降低”说明了如何解决问题。在UTF-8“INI文件”中的案例转换问题显示了在Windows INI文件中使用UTF-8的Windows API的实现 历史 2020年8月2日-本系列其他文章的链接,2019年11月22日代码更新-初始版本 本文转载于:http://www.diyabc.com/frontweb/news166.html

posted @ 2020-08-04 01:15  Dincat  阅读(562)  评论(0编辑  收藏  举报