在 Windows 中使用 boost::p rogram_options 从命令行参数读取 Unicode 字符

Reading Unicode characters from command line arguments using boost::program_options in Windows

本文关键字:options 命令行 参数 字符 Unicode 读取 rogram Windows boost      更新时间:2023-10-16

我有几个Windows应用程序从命令行参数读取文件路径。一切都完美无缺,除非传递带有非 ANSI 字符的路径。我预料到了这一点,但不知道如何处理它。可能是一个入门级的问题,但这让我发疯。

我当前的代码如下所示:

int main(int argc, char* argv[]) {
namespace po = boost::program_options;
po::options_description po_desc("Allowed options");
po_desc.add_options()
("file", po::value<std::string>(), "path to file");
po::variables_map po_vm;
try {
po::store(po::parse_command_line(argc, argv, po_desc), po_vm);
po::notify(po_vm);
} catch (...) {
std::cout << po_desc << std::endl;
return false;
}
const std::string file_path = po_vm["file"].as<std::string>();
// ...
}

我发现,如果我将file_path的类型从std::string替换为boost::filesystem::path,现在可以读取一些路径。我不知道确切的原因,但可以推断它必须是从拉丁语 1 字符集翻译而来的。

例如,具有以下文件:

malaga.txt
málaga.txt
mąlaga.txt

第一个始终正确读取,而第二个在使用std::string file_path时失败,但不是boost::filesystem::path file_path。第三个总是失败。

我尝试将 main 函数切换到int main(int argc, wchar_t* argv)并使用std::wstring作为参数类型,但它与boost::program_options解析器不兼容。

如何正确读取此类 Unicode 文件名?

感谢大家的评论,感谢他们,我设法解决了我的问题。

TL;博士

这里是固定代码:

int wmain(int argc, wchar_t* argv[]) { // <<<
namespace po = boost::program_options;
po::options_description po_desc("Allowed options");
po_desc.add_options()
("file", po::wvalue<std::wstring>(), "path to file") // <<<
("ansi", po::value<std::string>(), "an ANSI string")
;
po::variables_map po_vm;
try {
po::store(po::wcommand_line_parser(argc, argv) // <<<
.options(po_desc)
.run(),
po_vm);
po::notify(po_vm);
} catch (...) {
std::cout << po_desc << std::endl;
return false;
}
const boost::filesystem::path file_path = po_vm["file"].as<std::wstring>(); // <<<
// ...
}

解释

首先,切换到wmainwchar_t* argv:正如@erik-sun所提到的,有必要将入口点切换到Unicode感知功能。重要提示:可以使用int main(int, wchar_t*)(从某种意义上说它将编译(,但它不会接收具有正确编码的参数,解析器将失败,您必须使用wmain.

然后,@richard-critten 提供的 Unicode 支持链接对于理解编译错误非常有用:

  • 当类型为宽字符时,请使用boost::program_options::wvalue。内部实现使用字符串流:默认的仅适用于 8 位字符。
  • 使用boost::program_options::wcommand_line_parser接受wchar_t*参数。遗憾的是,此类没有多合一构造函数,您必须使用格式来分析命令行。
  • 最后,在需要时检索std::wstring值。

我扩展了代码片段,以表明它仍然与std::string输入兼容。

旁注

我的完整解决方案需要在某个时候实例化QtQApplicationQApplication构造函数与宽字符argv不兼容。由于不需要与Qt部分进行命令行交互(所有内容在Boost之前很久就已经处理了(,因此可以重写它以接收假参数:

int fake_argc = 1;
char* fake_argv[] = {"AplicationName"};
QApplication a(fake_argc, fake_argv);