Comment puis-je convertir wssortingng en u16ssortingng?

Je veux convertir wssortingng à u16ssortingng en C ++.

Je peux convertir wssortingng en chaîne, ou inverser. Mais je ne sais pas comment convertir en u16ssortingng .

 u16ssortingng CTextConverter::convertWssortingng2U16(wssortingng str) { int iSize; u16ssortingng szDest[256] = {}; memset(szDest, 0, 256); iSize = WideCharToMultiByte(CP_UTF8, NULL, str.c_str(), -1, NULL, 0,0,0); WideCharToMultiByte(CP_UTF8, NULL, str.c_str(), -1, szDest, iSize,0,0); u16ssortingng s16 = szDest; return s16; } 

Erreur dans WideCharToMultiByte (CP_UTF8, NULL, str.c_str (), -1, szDest, iSize, 0,0); ‘ szDest . La cause de u16ssortingng ne peut pas être utilisée avec LPSTR .

Comment puis-je réparer ce code?

Pour une solution indépendante de la plate-forme , voir cette réponse .

Si vous avez besoin d’une solution uniquement pour la plateforme Windows , le code suivant sera suffisant:

 std::wssortingng wstr( L"foo" ); std::u16ssortingng u16str( wstr.begin(), wstr.end() ); 

Sur la plate-forme Windows, std::wssortingng est interchangeable avec std::u16ssortingng car sizeof(wssortingng::value_type) == sizeof(u16ssortingng::value_type) et les deux sont codés en UTF-16 (little endian).

 wssortingng::value_type = wchar_t u16ssortingng::value_type = char16_t 

La seule différence étant que wchar_t est signé, alors que char16_t est non signé, il vous suffit donc de convertir les signatures, ce qui peut être effectué à l’aide du constructeur w16ssortingng qui prend une paire d’iterators en tant qu’arguments. Ce constructeur convertira implicitement wchar_t en char16_t .

Exemple d’application console complète:

 #include  #include  int main() { static_assert( sizeof(std::wssortingng::value_type) == sizeof(std::u16ssortingng::value_type), "std::wssortingng and std::u16ssortingng are expected to have the same character size" ); std::wssortingng wstr( L"foo" ); std::u16ssortingng u16str( wstr.begin(), wstr.end() ); // The u16ssortingng constructor performs an implicit conversion like: wchar_t wch = L'A'; char16_t ch16 = wch; // Need to reinterpret_cast because char16_t const* is not implicitly convertible // to LPCWSTR (aka wchar_t const*). ::MessageBoxW( 0, reinterpret_cast( u16str.c_str() ), L"test", 0 ); return 0; } 

Mettre à jour

J’avais pensé que la version standard ne fonctionnait pas, mais en réalité, c’était simplement dû à des bogues dans les bibliothèques d’exécution Visual C ++ et libstdc ++ 3.4.21. Cela fonctionne avec clang++ -std=c++14 -stdlib=libc++ . Voici une version qui teste si la méthode standard fonctionne sur votre compilateur:

 #include  #include  #include  #include  #include  #include  #include  #include  using std::cout; using std::endl; using std::exit; using std::memcmp; using std::size_t; using std::wcout; #if _WIN32 || _WIN64 // Windows needs a little non-standard magic for this to work. #include  #include  #include  #endif using std::size_t; void init_locale(void) // Does magic so that wcout can work. { #if _WIN32 || _WIN64 // Windows needs a little non-standard magic. constexpr char cp_utf16le[] = ".1200"; setlocale( LC_ALL, cp_utf16le ); _setmode( _fileno(stdout), _O_U16TEXT ); #else // The correct locale name may vary by OS, eg, "en_US.utf8". constexpr char locale_name[] = ""; std::locale::global(std::locale(locale_name)); std::wcout.imbue(std::locale()); #endif } int main(void) { constexpr char16_t msg_utf16[] = u"¡Hola, mundo! \U0001F600"; // Shouldn't assume endianness. constexpr wchar_t msg_w[] = L"¡Hola, mundo! \U0001F600"; constexpr char32_t msg_utf32[] = U"¡Hola, mundo! \U0001F600"; constexpr char msg_utf8[] = u8"¡Hola, mundo! \U0001F600"; init_locale(); const std::codecvt_utf16 converter_w; const size_t max_len = sizeof(msg_utf16); std::vector out(max_len); std::mbstate_t state; const wchar_t* from_w = nullptr; char* to_next = nullptr; converter_w.out( state, msg_w, msg_w+sizeof(msg_w)/sizeof(wchar_t), from_w, out.data(), out.data() + out.size(), to_next ); if (memcmp( msg_utf8, out.data(), sizeof(msg_utf8) ) == 0 ) { wcout << L"std::codecvt_utf16 converts to UTF-8, not UTF-16!" << endl; } else if ( memcmp( msg_utf16, out.data(), max_len ) != 0 ) { wcout << L"std::codecvt_utf16 conversion not equal!" << endl; } else { wcout << L"std::codecvt_utf16 conversion is correct." << endl; } out.clear(); out.resize(max_len); const std::codecvt_utf16 converter_u32; const char32_t* from_u32 = nullptr; converter_u32.out( state, msg_utf32, msg_utf32+sizeof(msg_utf32)/sizeof(char32_t), from_u32, out.data(), out.data() + out.size(), to_next ); if ( memcmp( msg_utf16, out.data(), max_len ) != 0 ) { wcout << L"std::codecvt_utf16 conversion not equal!" << endl; } else { wcout << L"std::codecvt_utf16 conversion is correct." << endl; } wcout << msg_w << endl; return EXIT_SUCCESS; } 

précédent

Un peu tard dans le jeu, mais voici une version qui vérifie en outre si wchar_t est 32 bits (comme sous Linux) et, le cas échéant, effectue une conversion par paire de substitution. Je recommande de sauvegarder cette source au format UTF-8 avec une nomenclature. Voici un lien vers celui-ci sur ideone.

 #include  #include  #include  #include  #include  #include  #include  #if _WIN32 || _WIN64 // Windows needs a little non-standard magic for this to work. #include  #include  #include  #endif using std::size_t; void init_locale(void) // Does magic so that wcout can work. { #if _WIN32 || _WIN64 // Windows needs a little non-standard magic. constexpr char cp_utf16le[] = ".1200"; setlocale( LC_ALL, cp_utf16le ); _setmode( _fileno(stdout), _O_U16TEXT ); #else // The correct locale name may vary by OS, eg, "en_US.utf8". constexpr char locale_name[] = ""; std::locale::global(std::locale(locale_name)); std::wcout.imbue(std::locale()); #endif } std::u16ssortingng make_u16ssortingng( const std::wssortingng& ws ) /* Creates a UTF-16 ssortingng from a wide-character ssortingng. Any wide characters * outside the allowed range of UTF-16 are mapped to the sentinel value U+FFFD, * per the Unicode documentation. (http://www.unicode.org/faq/private_use.html * resortingeved 12 March 2017.) Unpaired surrogates in ws are also converted to * sentinel values. Noncharacters, however, are left intact. As a fallback, * if wide characters are the same size as char16_t, this does a more sortingvial * construction using that implicit conversion. */ { /* We assume that, if this test passes, a wide-character ssortingng is already * UTF-16, or at least converts to it implicitly without needing surrogate * pairs. */ if ( sizeof(wchar_t) == sizeof(char16_t) ) { return std::u16ssortingng( ws.begin(), ws.end() ); } else { /* The conversion from UTF-32 to UTF-16 might possibly require surrogates. * A surrogate pair suffices to represent all wide characters, because all * characters outside the range will be mapped to the sentinel value * U+FFFD. Add one character for the terminating NUL. */ const size_t max_len = 2 * ws.length() + 1; // Our temporary UTF-16 ssortingng. std::u16ssortingng result; result.reserve(max_len); for ( const wchar_t& wc : ws ) { const std::wint_t chr = wc; if ( chr < 0 || chr > 0x10FFFF || (chr >= 0xD800 && chr <= 0xDFFF) ) { // Invalid code point. Replace with sentinel, per Unicode standard: constexpr char16_t sentinel = u'\uFFFD'; result.push_back(sentinel); } else if ( chr < 0x10000UL ) { // In the BMP. result.push_back(static_cast(wc)); } else { const char16_t leading = static_cast( ((chr-0x10000UL) / 0x400U) + 0xD800U ); const char16_t trailing = static_cast( ((chr-0x10000UL) % 0x400U) + 0xDC00U ); result.append({leading, trailing}); } // end if } // end for /* The returned ssortingng is shrunken to fit, which might not be the Right * Thing if there is more to be added to the ssortingng. */ result.shrink_to_fit(); // We depend here on the comstackr to optimize the move constructor. return result; } // end if // Not reached. } int main(void) { static const std::wssortingng wtest(L"☪☮∈✡℩☯✝ \U0001F644"); static const std::u16ssortingng u16test(u"☪☮∈✡℩☯✝ \U0001F644"); const std::u16ssortingng converted = make_u16ssortingng(wtest); init_locale(); std::wcout << L"sizeof(wchar_t) == " << sizeof(wchar_t) << L".\n"; for( size_t i = 0; i <= u16test.length(); ++i ) { if ( u16test[i] != converted[i] ) { std::wcout << std::hex << std::showbase << std::right << std::setfill(L'0') << std::setw(4) << (unsigned)converted[i] << L" ≠ " << std::setw(4) << (unsigned)u16test[i] << L" at " << i << L'.' << std::endl; return EXIT_FAILURE; } // end if } // end for std::wcout << wtest << std::endl; return EXIT_SUCCESS; } 

note de bas de page

Depuis que quelqu'un a demandé: La raison pour laquelle je suggère UTF-8 avec nomenclature est que certains compilateurs, y compris MSVC 2015, supposeront qu'un fichier source est codé conformément à la page de code actuelle, sauf s'il existe une nomenclature ou si vous spécifiez un codage sur la ligne de commande. Malheureusement, aucun encodage ne fonctionne sur toutes les chaînes d'outils, mais chaque outil que j'ai utilisé est suffisamment moderne pour prendre en charge C ++ 14 comprend également la nomenclature.