用Unicode、Boost、C++;,编解码器 在C++中,我想使用Unicode来做事情。因此,在跌入Unicode的兔子洞之后,我终于陷入了一场混乱、头痛和地域的火车失事
但在Boost中,我遇到了一个不幸的问题,即尝试使用Unicode文件路径,以及尝试使用带有Unicode输入的Boost程序选项库。我已经阅读了关于区域设置、codecvt、Unicode编码和Boost的所有内容 我目前的尝试是使用codecvt,它接受UTF-8字符串并将其转换为平台的编码(POSIX上的UTF-8,Windows上的UTF-16),我一直试图避免用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
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::coutstd::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;
}