用Unicode、Boost、C++;,编解码器 在C++中,我想使用Unicode来做事情。因此,在跌入Unicode的兔子洞之后,我终于陷入了一场混乱、头痛和地域的火车失事

用Unicode、Boost、C++;,编解码器 在C++中,我想使用Unicode来做事情。因此,在跌入Unicode的兔子洞之后,我终于陷入了一场混乱、头痛和地域的火车失事,c++,boost,unicode,codecvt,C++,Boost,Unicode,Codecvt,但在Boost中,我遇到了一个不幸的问题,即尝试使用Unicode文件路径,以及尝试使用带有Unicode输入的Boost程序选项库。我已经阅读了关于区域设置、codecvt、Unicode编码和Boost的所有内容 我目前的尝试是使用codecvt,它接受UTF-8字符串并将其转换为平台的编码(POSIX上的UTF-8,Windows上的UTF-16),我一直试图避免wchar\t 我实际得到的最接近的结果是尝试使用Boost.Locale实现这一点,在输出时将UTF-8字符串转换为UTF-3

但在Boost中,我遇到了一个不幸的问题,即尝试使用Unicode文件路径,以及尝试使用带有Unicode输入的Boost程序选项库。我已经阅读了关于区域设置、codecvt、Unicode编码和Boost的所有内容

我目前的尝试是使用codecvt,它接受UTF-8字符串并将其转换为平台的编码(POSIX上的UTF-8,Windows上的UTF-16),我一直试图避免
wchar\t

我实际得到的最接近的结果是尝试使用Boost.Locale实现这一点,在输出时将UTF-8字符串转换为UTF-32字符串

#include <string>
#include <boost/locale.hpp>
#include <locale>

int main(void)
{
  std::string data("Testing, 㤹");

  std::locale fromLoc = boost::locale::generator().generate("en_US.UTF-8");
  std::locale toLoc   = boost::locale::generator().generate("en_US.UTF-32");

  typedef std::codecvt<wchar_t, char, mbstate_t> cvtType;
  cvtType const* toCvt = &std::use_facet<cvtType>(toLoc);

  std::locale convLoc = std::locale(fromLoc, toCvt);

  std::cout.imbue(convLoc);
  std::cout << data << std::endl;

  // Output is unconverted -- what?

  return 0;
}
#包括
#包括
#包括
内部主(空)
{
字符串数据(“测试,㤹");
std::locale fromLoc=boost::locale::generator().generate(“en_US.UTF-8”);
std::locale toLoc=boost::locale::generator().generate(“en_US.UTF-32”);
typedef std::codevt cvtType;
cvtType const*toCvt=&std::use_facet(toLoc);
std::locale convLoc=std::locale(fromLoc,toCvt);
标准:cout.imbue(convLoc);
std::cout
std::cout.imbue(convLoc);

STD::CUT> P>在Visual C++中使用UTF16时,Boost文件系统IOSWATE替换类工作良好。 但是,它们不起作用(在支持任意文件名的意义上)在Windows中使用G++时,至少在Boost版本1.47中使用。有一个代码注释解释了:基本上,VisualC++标准库提供了非标准的<>代码> WCARGYT基于构造函数的增强文件系统类的构造函数,但是G++不支持这些扩展。 解决方法是使用8.3短文件名,但此解决方案有点脆弱,因为在旧Windows版本中,用户可以关闭自动生成短文件名


在Windows中使用Boost文件系统的示例代码:

#include "CmdLineArgs.h"        // CmdLineArgs
#include "throwx.h"             // throwX, hopefully
#include "string_conversions.h" // ansiOrFillerFrom( wstring )

#include <boost/filesystem/fstream.hpp>     // boost::filesystem::ifstream
#include <iostream>             // std::cout, std::cerr, std::endl
#include <stdexcept>            // std::runtime_error, std::exception
#include <string>               // std::string
#include <stdlib.h>             // EXIT_SUCCESS, EXIT_FAILURE
using namespace std;
namespace bfs = boost::filesystem;

inline string ansi( wstring const& ws ) { return ansiWithFillersFrom( ws ); }

int main()
{
    try
    {
        CmdLineArgs const   args;
        wstring const       programPath     = args.at( 0 );

        hopefully( args.nArgs() == 2 )
            || throwX( "Usage: " + ansi( programPath ) + " FILENAME" );

        wstring const       filePath        = args.at( 1 );
        bfs::ifstream       stream( filePath );     // Nice Boost ifstream subclass.
        hopefully( !stream.fail() )
            || throwX( "Failed to open file '" + ansi( filePath ) + "'" );

        string line;
        while( getline( stream, line ) )
        {
            cout << line << endl;
        }
        hopefully( stream.eof() )
            || throwX( "Failed to list contents of file '" + ansi( filePath ) + "'" );

        return EXIT_SUCCESS;
    }
    catch( exception const& x )
    {
        cerr << "!" << x.what() << endl;
    }
    return EXIT_FAILURE;
}
#包括“CmdLineArgs.h”//CmdLineArgs
#希望包括“throwx.h”//throwx
#包括“string_conversions.h”//ansiOrFillerFrom(wstring)
#包括//boost::filesystem::ifstream
#包括//std::cout、std::cerr、std::endl
#包括//标准::运行时错误,标准::异常
#include//std::string
#包括//退出成功,退出失败
使用名称空间std;
名称空间bfs=boost::filesystem;
内联字符串ansi(wstring const&ws){返回ansiWithFillersFrom(ws);}
int main()
{
尝试
{
CmdLineArgs常量参数;
wstring const programPath=args.at(0);
希望(args.nArgs()==2)
||throwX(“用法:”+ansi(程序路径)+“文件名”);
wstring const filePath=args.at(1);
ifstream(filePath);//漂亮的Boost ifstream子类。
希望(!stream.fail())
||throwX(“无法打开文件”“+ansi(文件路径)+”“””;
弦线;
while(getline(流,行))
{

好吧,经过几个月的思考,我终于明白了,我想在未来帮助人们

首先,codecvt的做法是错误的。Boost.Locale提供了一种在Boost::Locale::conv命名空间中的字符集之间进行转换的简单方法。下面是一个示例(其他示例不基于Locale)

#包括
名称空间loc=boost::locale;
内部主(空)
{
发电机发电机;
std::locale blah=gen.generate(“en_US.utf-32”);
std::string UTF8String=“Tésting!”;
//from_utf还可以处理宽字符串,因为它使用字符大小
//检测编码。
std::string converted=loc::conv::from_utf(UTF8String,blah);
//输出一个UTF-32字符串。

std::我可以试着跨平台做吗。@Jookia:好的。我假设你只限于UTF-8语言环境*nix(和Mac),和Windows。支持通用跨平台是我认为一个人做不到的。祝你好运!@Jookia:这个答案证明了我下面的一些说法。要在Windows上使用带unicode的boost.filesystem,你必须使用wstring,在非Windows上,你肯定要使用string。这就是boost.filesystem不隐藏平台差异的原因nd并没有使编写跨平台代码变得更简单。我必须承认,在boost.fs的情况下,您可以改变它将窄字符串解释为UTF-8的方式,从而使代码移植更容易。然而,关键是boost只需更改boost.fs中的两行代码就可以让我们的生活更轻松。遗憾的是,他们不想这样做。@ybungalobill:请注意,boost文件系统不支持windows中带有g++的通用文件名,并且该问题无法通过到处使用utf-8编码来解决。@AlfP.Steinbach对不起,你的确切意思是什么?如果它是根据boost_POSIX_API编译的,那么它确实不支持。如果它是根据boost_windows_API编译的,那么唯一不支持的部分就是是boost::filesystem::i/ofstream。他们可以通过直接使用winodows API实现filebuf来实现后者(我就是这么做的)。@Jookia:我不清楚您到底想要什么。您正试图输出一个编码未知的字符串(写入包含unicode字符的字符串文字已经不可移植)对CUT,它没有标准化的编码,你可以自由地假设它是什么编码。我总是假设用户让他的控制台配置UTF-8或者打开编辑器,了解UTF-8文件。我的代码不是整个问题,我一般都在处理Boost、C++、Loales和Unicode等问题。o在我的程序中使用UTF-8字符串,并将用户的区域设置从/转换为UTF-8,用于cout和cin,我不知道该怎么做。但是我想使用UTF-8和Boost,这似乎是不可能的,因为它使用宽字符串
#include "CmdLineArgs.h"        // CmdLineArgs
#include "throwx.h"             // throwX, hopefully
#include "string_conversions.h" // ansiOrFillerFrom( wstring )

#include <boost/filesystem/fstream.hpp>     // boost::filesystem::ifstream
#include <iostream>             // std::cout, std::cerr, std::endl
#include <stdexcept>            // std::runtime_error, std::exception
#include <string>               // std::string
#include <stdlib.h>             // EXIT_SUCCESS, EXIT_FAILURE
using namespace std;
namespace bfs = boost::filesystem;

inline string ansi( wstring const& ws ) { return ansiWithFillersFrom( ws ); }

int main()
{
    try
    {
        CmdLineArgs const   args;
        wstring const       programPath     = args.at( 0 );

        hopefully( args.nArgs() == 2 )
            || throwX( "Usage: " + ansi( programPath ) + " FILENAME" );

        wstring const       filePath        = args.at( 1 );
        bfs::ifstream       stream( filePath );     // Nice Boost ifstream subclass.
        hopefully( !stream.fail() )
            || throwX( "Failed to open file '" + ansi( filePath ) + "'" );

        string line;
        while( getline( stream, line ) )
        {
            cout << line << endl;
        }
        hopefully( stream.eof() )
            || throwX( "Failed to list contents of file '" + ansi( filePath ) + "'" );

        return EXIT_SUCCESS;
    }
    catch( exception const& x )
    {
        cerr << "!" << x.what() << endl;
    }
    return EXIT_FAILURE;
}
#include <boost/locale.hpp>
namespace loc = boost::locale;

int main(void)
{
  loc::generator gen;
  std::locale blah = gen.generate("en_US.utf-32");

  std::string UTF8String = "Tésting!";
  // from_utf will also work with wide strings as it uses the character size
  // to detect the encoding.
  std::string converted = loc::conv::from_utf(UTF8String, blah);

  // Outputs a UTF-32 string.
  std::cout << converted << std::endl;

  return 0;
}