一点前景:我的任务需要将UTF-8 XML文件转换为UTF-16(当然还有正确的标题).所以我搜索了将UTF-8转换为UTF-16的常用方法,并发现应该使用来自的模板<codecvt>.
但现在当它被弃用时,我想知道执行相同任务的新常用方法是什么?
(根本不介意使用Boost,但除此之外我更喜欢尽可能靠近标准库.)
我如何编写std :: codecvt方面?我喜欢写那些从UTF-16去UTF-8,从UTF-16去系统当前代码页(窗口,所以CP_ACP),以及系统的OEM代码页(窗口,所以CP_OEM).
跨平台是首选,但Windows上的MSVC也很好.关于如何正确使用这个类,是否有任何类型的教程或任何性质的东西?
在C++中,我想使用Unicode来做事情.因此,在掉下Unicode的兔子洞之后,我终于陷入了混乱,头痛和地方的火车残骸.
但是在Boost中,我遇到了一个不幸的问题,即尝试使用Unicode文件路径并尝试使用带有Unicode输入的Boost程序选项库.我已经阅读了关于locales,codecvts,Unicode编码和Boost主题的任何内容.
我目前试图让事情发挥作用的是使用一个带有UTF-8字符串的codecvt并将其转换为平台的编码(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;
}
Run Code Online (Sandbox Code Playgroud)
我想我还有其他一些转换工作使用宽字符,但我真的不知道我在做什么.我不知道这个工作的正确工具是什么.救命?
我一直在探索C++ 11的新Unicode功能,虽然其他C++ 11编码问题非常有用,但我对cppreference的以下代码片段有疑问 .代码写入然后立即读取以UTF-8编码保存的文本文件.
// Write
std::ofstream("text.txt") << u8"z\u6c34\U0001d10b";
// Read
std::wifstream file1("text.txt");
file1.imbue(std::locale("en_US.UTF8"));
std::cout << "Normal read from file (using default UTF-8/UTF-32 codecvt)\n";
for(wchar_t c; file1 >> c; ) // ?
std::cout << std::hex << std::showbase << c << '\n';
Run Code Online (Sandbox Code Playgroud)
我的问题非常简单,为什么循环中wchar_t需要for?一个u8文本字符串可以使用一个简单的声明char *和UTF-8编码的位布局应告诉系统字符的宽度.似乎有一些从UTF-8到UTF-32的自动转换(因此wchar_t),但如果是这种情况,为什么转换是必要的?
我使用Microsoft Visual Studio Community 2015 RC(版本14.0.22823.1 D14REL)收到与STL相关的链接错误
我正在链接一个C++ DLL并成功使用STL中的许多函数,但它找不到与std :: codecvt相关的东西:
error LNK2001: unresolved external symbol "__declspec(dllimport) public: static class std::locale::id std::codecvt<char32_t,char,struct _Mbstatet>::id" (__imp_?id@?$codecvt@_UDU_Mbstatet@@@std@@2V0locale@2@A)
Run Code Online (Sandbox Code Playgroud)
导致此问题的源代码引用:
std::wstring_convert< std::codecvt_utf8<char32_t>, char32_t > convert;
Run Code Online (Sandbox Code Playgroud)
我的代码生成是针对多线程dll的,我通过详细链接验证了在链接时搜索MSVCPRT.lib.
有任何想法吗 ?
\r要\r\n转换的C++ IO流的哪一部分?它stream_buf本身还是由codecvtfacet 进行内部到外部编码转换的一部分?
更新1
你们都说它是在streambuf/filebuf中完成的.好.但是这种安排如何处理,例如像UTF-16这样的外部编码?然后似乎必须打开文件ios::binary,禁用翻译.
std::codecvt_utf8<>以下是使用Facet 转换wchar_t为 UTF-8 的代码片段。使用 Visual Studio 2012,我的期望没有得到满足(请参阅代码末尾的条件)。我的期望是错误的吗?为什么?或者这是 Visual Studio 2012 库问题?
#include <locale>
#include <codecvt>
#include <cstdlib>
int main ()
{
std::mbstate_t state = std::mbstate_t ();
std::locale loc (std::locale (), new std::codecvt_utf8<wchar_t>);
typedef std::codecvt<wchar_t, char, std::mbstate_t> codecvt_type;
codecvt_type const & cvt = std::use_facet<codecvt_type> (loc);
wchar_t ch = L'\u5FC3';
wchar_t const * from_first = &ch;
wchar_t const * from_mid = &ch;
wchar_t const * from_end = from_first + 1;
char out_buf[1];
char * out_first = out_buf;
char * …Run Code Online (Sandbox Code Playgroud) 我一直在实现一个用于处理输出流标识的 codecvt。它可以像这样使用并且工作正常:
std::cout << indenter::push << "im indentet" << indenter::pop << "\n im not..."
Run Code Online (Sandbox Code Playgroud)
然而,虽然我可以将 an 灌输std::codecvt给任何std::ostream我,但当我发现我的代码可以与std::cout以及一起工作时,我感到非常困惑std::ofstream,但例如,std::ostringstream即使所有这些都继承自基类std::ostream。
facet正常构造,代码编译,它不会抛出任何异常......只是没有std::codecvt调用任何成员函数。
对我来说,这是非常令人困惑的,我不得不花很多时间弄清楚这std::codecvt不会对非文件 I/O 流做任何事情。
是否有任何原因std::codecvt没有被继承的所有类使用std::ostream?
此外,有没有人知道我可以依靠哪些结构来实现压头?
编辑:这是我所指语言的一部分:
通过 std::basic_fstream 执行的所有文件 I/O 操作使用流中灌输的语言环境的 std::codecvt<CharT, char, std::mbstate_t> 方面。
来源:https : //en.cppreference.com/w/cpp/locale/codecvt
我做了一个小例子来说明我的问题:
#include <iostream>
#include <locale>
#include <fstream>
#include <sstream>
static auto invocation_counter = 0u;
struct custom_facet : std::codecvt<char, char, std::mbstate_t>
{ …Run Code Online (Sandbox Code Playgroud) 我正在使用期望utf8编码的std :: string变量的代码.我希望能够处理用户提供的文件,该文件可能具有utf-16编码(我不知道设计时的编码,但最终希望能够处理utf8/16/32),读取它行-by-line,并将每一行转发给代码的其余部分作为utf8编码的std :: string.
我有c ++ 11(实际上,c ++ 11的当前MSVC子集)和1.55.0可以使用.我最终需要代码才能在Linux和Windows上运行.目前,我只是在Windows上使用Visual Studio 2013 Update 4进行原型设计,在Windows 7上运行.我对其他依赖项持开放态度,但他们需要建立一个已建立的跨平台(即windows和*nix)轨道记录,不应该是GPL/LGPL.
我一直在假设我似乎无法找到验证的方法,而且我的代码无效.
一个假设是,由于我最终希望std :: string变量中的这些文件中的每一行,我应该使用std :: ifstream,并使用正确构造的codecvt,以便传入的utf16流可以转换为utf8.
这个假设是否现实?我想,另一种选择是我必须对文本文件进行一些编码检查,然后根据结果选择wifstream/wstring或ifstream/string,这似乎比我想要开始时没有吸引力.当然,如果这是正确的(或唯一的现实的)路径,我愿意接受它.
我意识到我可能还需要进行一些编码检测,但就目前而言,我并不关心编码检测部分,只关注将utf16文件内容转换为utf8 std :: string.
我尝试过各种不同的locale和codecvt组合,但都没有.以下是我认为可行的最新版本,但不是:
void
SomeRandomClass::readUtf16LeFile( const std::string& theFileName )
{
boost::locale::generator gen;
std::ifstream file( theFileName );
auto utf8Locale = gen.generate( "UTF-8" );
std::locale cvtLocale( utf8Locale,
new std::codecvt_utf8_utf16<char>() );
file.imbue( utf8Locale );
std::string line;
std::cout.imbue( utf8Locale );
for ( int i = 0; i < 3; i++ )
{
std::getline( file, line );
std::cout << line << …Run Code Online (Sandbox Code Playgroud) 我遇到了两个代码片段
std::wstring str = std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>>().from_bytes("some utf8 string");
Run Code Online (Sandbox Code Playgroud)
和,
std::wstring str = std::wstring_convert<std::codecvt_utf8<wchar_t>>().from_bytes("some utf8 string");
Run Code Online (Sandbox Code Playgroud)
它们是否都是将存储的 utf-8 转换std::string为 utf-16 的正确方法std::wstring?