【问题标题】:Reading Unicode characters from command line arguments using boost::program_options in Windows在 Windows 中使用 boost::program_options 从命令行参数中读取 Unicode 字符
【发布时间】:2020-03-27 07:47:03
【问题描述】:

我有几个从命令行参数读取文件路径的 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 文件名?

【问题讨论】:

  • 也许你需要先chcp 65001
  • 通过 chcp.com 设置控制台代码页与此无关。 Windows 中的本机命令行是 Unicode (UTF-16LE)。问题是 C 运行时的main 入口点解析来自GetCommandLineA 的命令行的ANSI 编码,而不是来自GetCommandLineW 的Unicode 命令行。非标准的wmain 入口点基于本机Unicode 命令行。如果应用程序需要字节字符串,wchar_t 字符串可以通过WideCharToMultiByte 编码为 UTF-8。
  • 谢谢大家,你们的cmets很有用!

标签: c++ windows unicode command-line-arguments boost-program-options


【解决方案1】:

感谢大家为他们的 cmets 做出贡献,感谢他们,我设法解决了我的问题。

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>(); // <<<

    // ...
}

说明

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

那么,@richard-critten 提供的Unicode support link 对理解编译错误非常有用:

  • 当类型是宽字符时使用boost::program_options::wvalue。内部实现使用字符串流:默认的仅适用于 8 位字符。
  • 使用boost::program_options::wcommand_line_parser 接受wchar_t* 参数。不幸的是,这个类没有一体化的构造函数,你必须使用 long 形式来解析命令行。
  • 最后,在需要时将值检索为std::wstring

我已经扩展了代码 sn-p 以表明它仍然与 std::string 输入兼容。

旁注

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-02
    • 2019-09-16
    • 2015-04-07
    • 1970-01-01
    • 1970-01-01
    • 2015-07-26
    • 1970-01-01
    相关资源
    最近更新 更多