Стандартно кодиране на:
- Windows UTF-16.
- Linux UTF-8.
- MacOS UTF-8.
Стъпките на моето решение включват нулеви знаци \0 (избягвайте съкращаване). Без използване на функции в заглавката на windows.h:
- Добавете макроси за откриване на платформа.
#if defined (_WIN32)
#define WINDOWSLIB 1
#elif defined (__ANDROID__) || defined(ANDROID)//Android
#define ANDROIDLIB 1
#elif defined (__APPLE__)//iOS, Mac OS
#define MACOSLIB 1
#elif defined (__LINUX__) || defined(__gnu_linux__) || defined(__linux__)//_Ubuntu - Fedora - Centos - RedHat
#define LINUXLIB 1
#endif
- Създайте функции за преобразуване std::wstring в std::string или обратно.
#include <locale>
#include <iostream>
#include <string>
#ifdef WINDOWSLIB
#include <Windows.h>
#endif
using namespace std::literals::string_literals;
// Convert std::wstring to std::string
std::string WidestringToString(const std::wstring& wstr, const std::string& locale)
{
if (wstr.empty())
{
return std::string();
}
size_t pos;
size_t begin = 0;
std::string ret;
size_t size;
#ifdef WINDOWSLIB
_locale_t lc = _create_locale(LC_ALL, locale.c_str());
pos = wstr.find(static_cast<wchar_t>(0), begin);
while (pos != std::wstring::npos && begin < wstr.length())
{
std::wstring segment = std::wstring(&wstr[begin], pos - begin);
_wcstombs_s_l(&size, nullptr, 0, &segment[0], _TRUNCATE, lc);
std::string converted = std::string(size, 0);
_wcstombs_s_l(&size, &converted[0], size, &segment[0], _TRUNCATE, lc);
ret.append(converted);
begin = pos + 1;
pos = wstr.find(static_cast<wchar_t>(0), begin);
}
if (begin <= wstr.length()) {
std::wstring segment = std::wstring(&wstr[begin], wstr.length() - begin);
_wcstombs_s_l(&size, nullptr, 0, &segment[0], _TRUNCATE, lc);
std::string converted = std::string(size, 0);
_wcstombs_s_l(&size, &converted[0], size, &segment[0], _TRUNCATE, lc);
converted.resize(size - 1);
ret.append(converted);
}
_free_locale(lc);
#elif defined LINUXLIB
std::string currentLocale = setlocale(LC_ALL, nullptr);
setlocale(LC_ALL, locale.c_str());
pos = wstr.find(static_cast<wchar_t>(0), begin);
while (pos != std::wstring::npos && begin < wstr.length())
{
std::wstring segment = std::wstring(&wstr[begin], pos - begin);
size = wcstombs(nullptr, segment.c_str(), 0);
std::string converted = std::string(size, 0);
wcstombs(&converted[0], segment.c_str(), converted.size());
ret.append(converted);
ret.append({ 0 });
begin = pos + 1;
pos = wstr.find(static_cast<wchar_t>(0), begin);
}
if (begin <= wstr.length()) {
std::wstring segment = std::wstring(&wstr[begin], wstr.length() - begin);
size = wcstombs(nullptr, segment.c_str(), 0);
std::string converted = std::string(size, 0);
wcstombs(&converted[0], segment.c_str(), converted.size());
ret.append(converted);
}
setlocale(LC_ALL, currentLocale.c_str());
#elif defined MACOSLIB
#endif
return ret;
}
// Convert std::string to std::wstring
std::wstring StringToWideString(const std::string& str, const std::string& locale)
{
if (str.empty())
{
return std::wstring();
}
size_t pos;
size_t begin = 0;
std::wstring ret;
size_t size;
#ifdef WINDOWSLIB
_locale_t lc = _create_locale(LC_ALL, locale.c_str());
pos = str.find(static_cast<char>(0), begin);
while (pos != std::string::npos) {
std::string segment = std::string(&str[begin], pos - begin);
std::wstring converted = std::wstring(segment.size() + 1, 0);
_mbstowcs_s_l(&size, &converted[0], converted.size(), &segment[0], _TRUNCATE, lc);
converted.resize(size - 1);
ret.append(converted);
ret.append({ 0 });
begin = pos + 1;
pos = str.find(static_cast<char>(0), begin);
}
if (begin < str.length()) {
std::string segment = std::string(&str[begin], str.length() - begin);
std::wstring converted = std::wstring(segment.size() + 1, 0);
_mbstowcs_s_l(&size, &converted[0], converted.size(), &segment[0], _TRUNCATE, lc);
converted.resize(size - 1);
ret.append(converted);
}
_free_locale(lc);
#elif defined LINUXLIB
std::string currentLocale = setlocale(LC_ALL, nullptr);
setlocale(LC_ALL, locale.c_str());
pos = str.find(static_cast<char>(0), begin);
while (pos != std::string::npos) {
std::string segment = std::string(&str[begin], pos - begin);
std::wstring converted = std::wstring(segment.size(), 0);
size = mbstowcs(&converted[0], &segment[0], converted.size());
converted.resize(size);
ret.append(converted);
ret.append({ 0 });
begin = pos + 1;
pos = str.find(static_cast<char>(0), begin);
}
if (begin < str.length()) {
std::string segment = std::string(&str[begin], str.length() - begin);
std::wstring converted = std::wstring(segment.size(), 0);
size = mbstowcs(&converted[0], &segment[0], converted.size());
converted.resize(size);
ret.append(converted);
}
setlocale(LC_ALL, currentLocale.c_str());
#elif defined MACOSLIB
#endif
return ret;
}
- Отпечатайте std::string. Проверете Суфикс на RawString.
Linux код. Отпечатайте директно std::string с помощта на std::cout.
Ако имате std::wstring.
1. Преобразувайте в std::string.
2. Отпечатайте със std::cout.
std::wstring x = L"\0\001日本ABC\0DE\0F\0G????\0"s;
std::string result = WidestringToString(x, "en_US.UTF-8");
std::cout << "RESULT=" << result << std::endl;
std::cout << "RESULT_SIZE=" << result.size() << std::endl;
В Windows, ако трябва да отпечатате unicode. Трябва да използваме WriteConsole за печат на уникод знаци от std::wstring или std::string.
void WriteUnicodeLine(const std::string& s)
{
#ifdef WINDOWSLIB
WriteUnicode(s);
std::cout << std::endl;
#elif defined LINUXLIB
std::cout << s << std::endl;
#elif defined MACOSLIB
#endif
}
void WriteUnicode(const std::string& s)
{
#ifdef WINDOWSLIB
std::wstring unicode = Insane::String::Strings::StringToWideString(s);
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), unicode.c_str(), static_cast<DWORD>(unicode.length()), nullptr, nullptr);
#elif defined LINUXLIB
std::cout << s;
#elif defined MACOSLIB
#endif
}
void WriteUnicodeLineW(const std::wstring& ws)
{
#ifdef WINDOWSLIB
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), ws.c_str(), static_cast<DWORD>(ws.length()), nullptr, nullptr);
std::cout << std::endl;
#elif defined LINUXLIB
std::cout << String::Strings::WidestringToString(ws)<<std::endl;
#elif defined MACOSLIB
#endif
}
void WriteUnicodeW(const std::wstring& ws)
{
#ifdef WINDOWSLIB
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), ws.c_str(), static_cast<DWORD>(ws.length()), nullptr, nullptr);
#elif defined LINUXLIB
std::cout << String::Strings::WidestringToString(ws);
#elif defined MACOSLIB
#endif
}
Код на Windows. Използване на функцията WriteLineUnicode или WriteUnicode. Същият код може да се използва за Linux.
std::wstring x = L"\0\001日本ABC\0DE\0F\0G????\0"s;
std::string result = WidestringToString(x, "en_US.UTF-8");
WriteLineUnicode(u8"RESULT" + result);
WriteLineUnicode(u8"RESULT_SIZE" + std::to_string(result.size()));
Най-накрая в Windows. Имате нужда от мощна и пълна поддръжка за уникод знаци в конзолата. Препоръчвам ConEmu и задайте като терминал по подразбиране в Windows.
Тествайте на Microsoft Visual Studio и Jetbrains Clion.
- Тествано на Microsoft Visual Studio 2017 с VC++; std=c++17. (проект на Windows)
- Тествано на Microsoft Visual Studio 2017 с g++; std=c++17. (Проект Linux)
- Тествано на Jetbrains Clion 2018.3 с g++; std=c++17. (Linux Toolchain / Дистанционно)
QA
В. Защо не използвате <codecvt>
заглавни функции и класове?.
А. Отхвърляне на Премахнати или отхвърлени функции невъзможно изграждане на VC++, но няма проблеми на g++. Предпочитам 0 предупреждения и главоболия.
Q. wstring в Windows са взаимозаменяеми.
A. Отхвърляне на Премахнати или остарели функции невъзможно изграждане на VC++, но няма проблеми на g++. Предпочитам 0 предупреждения и главоболия.
В. std ::wstring е междуплатформен?
А. Не. std::wstring използва wchar_t елементи. В Windows размерът wchar_t е 2 байта, всеки символ се съхранява в UTF-16 единици, ако знакът е по-голям от U+FFFF, символът се представя в две UTF-16 единици (2 wchar_t елемента), наречени сурогатни двойки. В Linux wchar_t размерът е 4 байта, всеки символ се съхранява в един wchar_t елемент, не са необходими сурогатни двойки. Проверете Стандартен типове данни в UNIX, Linux и Windows.
В. std ::string е междуплатформен?
А. Да. std::string използва char елементи. типът char е гарантиран, че е с еднакъв размер на байта във всички компилатори. размерът на типа char е 1 байт. Проверете Стандартен типове данни в UNIX, Linux и Windows.
person
Joma
schedule
22.02.2019
WriteConsoleW
– ако не стане не работи с това, тогава е невъзможно. - person user541686   schedule 29.01.2012