使用 Windows 中的 boost::program_options 从命令行参数读取 Unicode 字符
Reading Unicode characters from command line arguments using boost::program_options in Windows
我有几个 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
,现在会读取一些路径。我不知道确切原因,但可以推断它必须与 Latin1 字符集的翻译有关。
例如,有以下文件:
malaga.txt
málaga.txt
mąlaga.txt
第一个总是正确读取,而第二个在使用 std::string file_path
而不是 boost::filesystem::path file_path
时失败。第三个总是失败。
我试过将主函数切换到 int main(int argc, wchar_t* argv)
并使用 std::wstring
作为参数类型,但它与 boost::program_options
解析器不兼容。
如何正确读取此类 Unicode 文件名?
感谢大家发表评论,多亏了他们,我才设法解决了我的问题。
TL;DR
这里是固定代码:
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>(); // <<<
// ...
}
说明
首先,切换到wmain
和wchar_t* argv
:如所述,有必要将入口点切换到支持Unicode的函数。重要说明:可以使用 int main(int, wchar_t*)
(在某种意义上它会编译)但它不会接收具有正确编码的参数并且解析器将失败,你必须使用 wmain
.
然后,Unicode support link provided by 对于理解编译错误非常有用:
- 当类型为宽字符时使用
boost::program_options::wvalue
。内部实现使用字符串流:默认的仅适用于 8 位字符。
- 使用
boost::program_options::wcommand_line_parser
接受wchar_t*
参数。不幸的是,这个 class 没有一个一体化的构造函数,你必须使用 long 形式来解析命令行。
- 最后,在需要时将值检索为
std::wstring
。
我扩展了代码片段以表明它仍然与 std::string
输入兼容。
旁注
我的完整解决方案需要在某个时候实例化 Qt QApplication
。 QApplication
构造函数与宽字符 argv
不兼容。由于 Qt 部分不需要命令行交互(一切都在很久之前由 Boost 处理),它可以被重写以接收假参数:
int fake_argc = 1;
char* fake_argv[] = {"AplicationName"};
QApplication a(fake_argc, fake_argv);
我有几个 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
,现在会读取一些路径。我不知道确切原因,但可以推断它必须与 Latin1 字符集的翻译有关。
例如,有以下文件:
malaga.txt
málaga.txt
mąlaga.txt
第一个总是正确读取,而第二个在使用 std::string file_path
而不是 boost::filesystem::path file_path
时失败。第三个总是失败。
我试过将主函数切换到 int main(int argc, wchar_t* argv)
并使用 std::wstring
作为参数类型,但它与 boost::program_options
解析器不兼容。
如何正确读取此类 Unicode 文件名?
感谢大家发表评论,多亏了他们,我才设法解决了我的问题。
TL;DR
这里是固定代码:
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>(); // <<<
// ...
}
说明
首先,切换到wmain
和wchar_t* argv
:如int main(int, wchar_t*)
(在某种意义上它会编译)但它不会接收具有正确编码的参数并且解析器将失败,你必须使用 wmain
.
然后,Unicode support link provided by
- 当类型为宽字符时使用
boost::program_options::wvalue
。内部实现使用字符串流:默认的仅适用于 8 位字符。 - 使用
boost::program_options::wcommand_line_parser
接受wchar_t*
参数。不幸的是,这个 class 没有一个一体化的构造函数,你必须使用 long 形式来解析命令行。 - 最后,在需要时将值检索为
std::wstring
。
我扩展了代码片段以表明它仍然与 std::string
输入兼容。
旁注
我的完整解决方案需要在某个时候实例化 Qt QApplication
。 QApplication
构造函数与宽字符 argv
不兼容。由于 Qt 部分不需要命令行交互(一切都在很久之前由 Boost 处理),它可以被重写以接收假参数:
int fake_argc = 1;
char* fake_argv[] = {"AplicationName"};
QApplication a(fake_argc, fake_argv);