在Windows

时间:2017-08-08 15:20:22

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

我们将路径表示为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。

获取std::string的{​​{1}}表示形式的最佳方法(如果可能的话,可移植)是什么,确保在必要时从正确的path编码进行转换?

1 个答案:

答案 0 :(得分:3)

  

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

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

  

获得最佳方式(如果可能的话,便携式)是什么?   std :: string表示路径,确保从中转换   必要时正确编码wchar_t?

C ++ 11标准引入了std::codecvt_utf8_utf16。虽然从C++17开始不推荐使用,但根据this paper,它可以使用"直到合适的替代品标准化为止#34;

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

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

之后,对path::string()的所有呼叫都将从UTF-16转换为UTF-8。

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

完整的示例代码:

#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';
}