【问题标题】:Getting a boost::filesystem::path as an UTF-8 encoded std::string, on Windows在 Windows 上获取 boost::filesystem::path 作为 UTF-8 编码的 std::string
【发布时间】:2018-01-16 06:04:34
【问题描述】:

我们将路径表示为 boost::filesystem::path,但在某些情况下,其他 API 期望它们为 const char *(例如,使用 SQLite 打开数据库文件)。

来自the documentationpath::value_type是Windows下的wchar_t。据我所知,Windows wchar_t 是 2 个字节,UTF-16 编码。

有一个string()本地观察者返回一个std::string,同时声明:

如果 string_type 是不同于 String 的类型,则转换是 由 cvt 执行。

cvt 被初始化为默认构造的codecvt。这个默认构造的 codecvt 的行为是什么?

this forum entry,建议使用utf8_codecvt_facet 的实例作为cvt 的值,以便可移植地转换为UTF-8。不过貌似这个codecvt其实是要转换between UTF-8 and UCS-4,而不是UTF-16。

什么是获得pathstd::string 表示的最佳方式(如果可能的话可移植),并确保在必要时从正确的wchar_t 编码转换?

【问题讨论】:

    标签: c++ encoding utf-8 boost-filesystem


    【解决方案1】:

    cvt 被初始化为默认构造的codecvt。是什么 这个默认构造的 codecvt 的行为?

    它使用默认语言环境来转换为特定于语言环境的多字节字符集。在 Windows 上,此区域设置通常对应于控制面板中的区域设置。

    获得 std::string 表示路径,确保从 必要时正确的 wchar_t 编码?

    C++11 标准引入std::codecvt_utf8_utf16。尽管自 C++17 起已弃用,但根据 this paper 的说法,它将“在合适的替代品标准化之前”可用。

    要使用这个方面,请调用静态函数:

    boost::filesystem::path::imbue( 
        std::locale( std::locale(), new std::codecvt_utf8_utf16<wchar_t>() ) );
    

    之后,所有对 path::string() 的调用都会从 UTF-16 转换为 UTF-8。

    另一种方法是仅在某些情况下使用std::wstring_convert&lt; std::codecvt_utf8_utf16&lt;wchar_t&gt; &gt; 进行转换。

    完整示例代码:

    #include <boost/filesystem.hpp>
    #include <iostream>
    #include <codecvt>
    
    void print_hex( std::string const& path );
    
    int main()
    {
        // Create UTF-16 path (on Windows) that contains the characters "ÄÖÜ".
        boost::filesystem::path path( L"\u00c4\u00d6\u00dc" );
    
        // Convert path using the default locale and print result.
        // On a system with german default locale, this prints "0xc4 0xd6 0xdc".
        // On a system with a different locale, this might fail.
        print_hex( path.string() );
    
        // Set locale for conversion from UTF-16 to UTF-8.
        boost::filesystem::path::imbue( 
            std::locale( std::locale(), new std::codecvt_utf8_utf16<wchar_t>() ) );
    
        // Because we changed the locale, path::string() now converts the path to UTF-8.
        // This always prints the UTF-8 bytes "0xc3 0x84 0xc3 0x96 0xc3 0x9c".
        print_hex( path.string() );
    
        // Another option is to convert only case-by-case, by explicitly using a code converter.
        // This always prints the UTF-8 bytes "0xc3 0x84 0xc3 0x96 0xc3 0x9c".
        std::wstring_convert< std::codecvt_utf8_utf16<wchar_t> > cvt;
        print_hex( cvt.to_bytes( path.wstring() ) );
    }
    
    void print_hex( std::string const& path )
    {
        for( char c : path )
        {
            std::cout << std::hex << "0x" << static_cast<unsigned>(static_cast<unsigned char>( c )) << ' ';
        }
        std::cout << '\n';
    }
    

    【讨论】:

    • 这个 path.imbue 调用具有误导性 - boost::filesystem::path::imbue 是一个影响全局状态的静态函数,而不是 path 变量本身。
    • @sms 很好。我已更改为 :: 表示法并明确提及它是一个静态函数。
    • C++1x 不是标准。你是说 C++11 吗?还是您的意思是 C++11 & C++14 & C++17?请澄清。
    • @LightnessRacesinOrbit 完成。
    猜你喜欢
    • 2011-04-23
    • 2018-02-18
    • 2013-09-26
    • 1970-01-01
    • 2011-05-03
    • 1970-01-01
    • 2013-09-11
    • 1970-01-01
    相关资源
    最近更新 更多