如何将wstring转换为字符串?

问题是如何将wstring转换为字符串?

我还有一个例子:

#include <string>
#include <iostream>


int main()
{
std::wstring ws = L"Hello";
std::string s( ws.begin(), ws.end() );


//std::cout <<"std::string =     "<<s<<std::endl;
std::wcout<<"std::wstring =    "<<ws<<std::endl;
std::cout <<"std::string =     "<<s<<std::endl;
}

带注释的输出为:

std::string =     Hello
std::wstring =    Hello
std::string =     Hello

但是without只是:

std::wstring =    Hello

这个例子中有什么问题吗?我可以像上面那样进行转换吗?

编辑

新例子(考虑到一些答案)是

#include <string>
#include <iostream>
#include <sstream>
#include <locale>


int main()
{
setlocale(LC_CTYPE, "");


const std::wstring ws = L"Hello";
const std::string s( ws.begin(), ws.end() );


std::cout<<"std::string =     "<<s<<std::endl;
std::wcout<<"std::wstring =    "<<ws<<std::endl;


std::stringstream ss;
ss << ws.c_str();
std::cout<<"std::stringstream =     "<<ss.str()<<std::endl;
}

输出结果为:

std::string =     Hello
std::wstring =    Hello
std::stringstream =     0x860283c

因此,不能使用stringstream将wstring转换为string。

379149 次浏览

我相信官方的方法仍然是通过codecvt facet(你需要某种语言环境感知的翻译),如在

resultCode = use_facet<codecvt<char, wchar_t, ConversionState> >(locale).
in(stateVar, scratchbuffer, scratchbufferEnd, from, to, toLimit, curPtr);

或者类似的东西,我没有工作代码。但我不确定现在有多少人使用这种机器,有多少人只是要求内存指针,让ICU或其他库处理血腥的细节。

代码有两个问题:

  1. const std::string s( ws.begin(), ws.end() );中的转换不需要正确地将宽字符映射到窄字符。最有可能的是,每个宽字符将被类型转换为char.
    这个问题的解决方案已经在答案是kem中给出,并涉及区域设置的ctype facet的narrow函数 你在同一个程序中同时向std::coutstd::wcout写入输出。coutwcout都与同一个流(stdout)相关联,并且没有定义将同一流同时用作面向字节的流(如cout)和面向宽的流(如wcout)的结果 最好的选择是避免将窄输出和宽输出混合到同一个(底层)流。对于stdout/cout/wcout,您可以尝试在宽输出和窄输出之间切换时切换stdout的方向(反之亦然):

    #include <iostream>
    #include <stdio.h>
    #include <wchar.h>
    
    
    int main() {
    std::cout << "narrow" << std::endl;
    fwide(stdout, 1); // switch to wide
    std::wcout << L"wide" << std::endl;
    fwide(stdout, -1); // switch to narrow
    std::cout << "narrow" << std::endl;
    fwide(stdout, 1); // switch to wide
    std::wcout << L"wide" << std::endl;
    }
    

下面是一个基于其他建议的解决方案:

#include <string>
#include <iostream>
#include <clocale>
#include <locale>
#include <vector>


int main() {
std::setlocale(LC_ALL, "");
const std::wstring ws = L"ħëłlö";
const std::locale locale("");
typedef std::codecvt<wchar_t, char, std::mbstate_t> converter_type;
const converter_type& converter = std::use_facet<converter_type>(locale);
std::vector<char> to(ws.length() * converter.max_length());
std::mbstate_t state;
const wchar_t* from_next;
char* to_next;
const converter_type::result result = converter.out(state, ws.data(), ws.data() + ws.length(), from_next, &to[0], &to[0] + to.size(), to_next);
if (result == converter_type::ok or result == converter_type::noconv) {
const std::string s(&to[0], to_next);
std::cout <<"std::string =     "<<s<<std::endl;
}
}

这通常适用于Linux,但会在Windows上产生问题。

在写这个答案的时候,第一个谷歌搜索“转换字符串wstring”会让你进入这个页面。我的回答展示了如何将字符串转换为wstring,虽然这不是实际的问题,我应该删除这个答案,但这被认为是糟糕的形式。你可能想跳到这个StackOverflow的答案,它现在的排名比本页更高。


这是一种将字符串,wstring和混合字符串常量组合到wstring的方法。使用wstringstream类。

#include <sstream>


std::string narrow = "narrow";
std::wstring wide = "wide";


std::wstringstream cls;
cls << " abc " << narrow.c_str() << L" def " << wide.c_str();
std::wstring total= cls.str();

你也可以直接使用ctype facet的narrow方法:

#include <clocale>
#include <locale>
#include <string>
#include <vector>


inline std::string narrow(std::wstring const& text)
{
std::locale const loc("");
wchar_t const* from = text.c_str();
std::size_t const len = text.size();
std::vector<char> buffer(len + 1);
std::use_facet<std::ctype<wchar_t> >(loc).narrow(from, from + len, '_', &buffer[0]);
return std::string(&buffer[0], &buffer[len]);
}

而不是包括locale和所有那些花哨的东西,如果你知道为FACT你的字符串是可转换的,只需这样做:

#include <iostream>
#include <string>


using namespace std;


int main()
{
wstring w(L"bla");
string result;
for(char x : w)
result += x;


cout << result << '\n';
}

活生生的例子在这里

旧的解决方案:http://forums.devshed.com/c-programming-42/wstring-to-string-444006.html

std::wstring wide( L"Wide" );
std::string str( wide.begin(), wide.end() );


// Will print no problemo!
std::cout << str << std::endl;

更新(2021):然而,至少在MSVC的最新版本上,这可能会生成wchar_tchar截断警告。可以通过使用std::transform代替转换函数中的显式转换来消除警告,例如:

std::wstring wide( L"Wide" );


std::string str;
std::transform(wide.begin(), wide.end(), std::back_inserter(str), [] (wchar_t c) {
return (char)c;
});

或者如果你更喜欢预分配而不使用back_inserter:

std::string str(wide.length(), 0);
std::transform(wide.begin(), wide.end(), str.begin(), [] (wchar_t c) {
return (char)c;
});

参见各种编译器在这里的示例。


当心,这里根本没有进行没有字符集转换。这只是简单地将每个迭代的wchar_t赋值给char—截断转换。它使用c 'tor std:: string:

template< class InputIt >
basic_string( InputIt first, InputIt last,
const Allocator& alloc = Allocator() );

如评论所述:

值0-127在几乎所有编码中都是相同的,因此截断 所有小于127的值都会生成相同的文本。输入一个

.

.

windows codepage 1252的值128-255 (windows English 默认值)和unicode的值128-255基本相同,因此如果 这就是你所使用的大部分字符的代码页 截断为正确的值。(我完全期待á和õ能正常工作, 我知道我们的代码在工作中依赖于é,我将很快修复)

并注意,Win12520x80 - 0x9F范围内的代码点将工作。这包括œžŸ,…

正如Cubbi在其中一条评论中指出的那样,std::wstring_convert (c++ 11)提供了一个简洁的解决方案(你需要#include <locale><codecvt>):

std::wstring string_to_convert;


//setup converter
using convert_type = std::codecvt_utf8<wchar_t>;
std::wstring_convert<convert_type, wchar_t> converter;


//use converter (.to_bytes: wstr->str, .from_bytes: str->wstr)
std::string converted_str = converter.to_bytes( string_to_convert );

在遇到这个问题之前,我正在使用wcstombs和繁琐的内存分配/释放的组合。

http://en.cppreference.com/w/cpp/locale/wstring_convert

更新(2013.11.28)

有一句话可以这样说(谢谢你的评论):

std::wstring str = std::wstring_convert<std::codecvt_utf8<wchar_t>>().from_bytes("some string");

包装器函数可以这样表述:(感谢ArmanSchwarz的评论)

std::wstring s2ws(const std::string& str)
{
using convert_typeX = std::codecvt_utf8<wchar_t>;
std::wstring_convert<convert_typeX, wchar_t> converterX;


return converterX.from_bytes(str);
}


std::string ws2s(const std::wstring& wstr)
{
using convert_typeX = std::codecvt_utf8<wchar_t>;
std::wstring_convert<convert_typeX, wchar_t> converterX;


return converterX.to_bytes(wstr);
}

注意:string/wstring是否应该作为引用或文字传递给函数存在一些争议(由于c++ 11和编译器更新)。我将把决定留给执行的人,但这是值得了解的。

注意:我在上面的代码中使用std::codecvt_utf8,但如果你不使用UTF-8,你需要将其更改为你正在使用的适当编码:

http://en.cppreference.com/w/cpp/header/codecvt

在我的情况下,我必须使用多字节字符(MBCS),我想使用std::string和std::wstring。不能使用c++11。所以我使用mbstowcs和wcstombs。

我与使用new, delete[]做相同的函数,但它比这更慢。

这可以帮助如何:在各种字符串类型之间转换

编辑

然而,在转换为wstring和源字符串是没有字母和多字节字符串的情况下,它是不工作的。 所以我把wcstombs改为WideCharToMultiByte.

#include <string>


std::wstring get_wstr_from_sz(const char* psz)
{
//I think it's enough to my case
wchar_t buf[0x400];
wchar_t *pbuf = buf;
size_t len = strlen(psz) + 1;


if (len >= sizeof(buf) / sizeof(wchar_t))
{
pbuf = L"error";
}
else
{
size_t converted;
mbstowcs_s(&converted, buf, psz, _TRUNCATE);
}


return std::wstring(pbuf);
}


std::string get_string_from_wsz(const wchar_t* pwsz)
{
char buf[0x400];
char *pbuf = buf;
size_t len = wcslen(pwsz)*2 + 1;


if (len >= sizeof(buf))
{
pbuf = "error";
}
else
{
size_t converted;
wcstombs_s(&converted, buf, pwsz, _TRUNCATE);
}


return std::string(pbuf);
}

编辑使用“MultiByteToWideChar”而不是“wcstombs”

#include <Windows.h>
#include <boost/shared_ptr.hpp>
#include "string_util.h"


std::wstring get_wstring_from_sz(const char* psz)
{
int res;
wchar_t buf[0x400];
wchar_t *pbuf = buf;
boost::shared_ptr<wchar_t[]> shared_pbuf;


res = MultiByteToWideChar(CP_ACP, 0, psz, -1, buf, sizeof(buf)/sizeof(wchar_t));


if (0 == res && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
res = MultiByteToWideChar(CP_ACP, 0, psz, -1, NULL, 0);


shared_pbuf = boost::shared_ptr<wchar_t[]>(new wchar_t[res]);


pbuf = shared_pbuf.get();


res = MultiByteToWideChar(CP_ACP, 0, psz, -1, pbuf, res);
}
else if (0 == res)
{
pbuf = L"error";
}


return std::wstring(pbuf);
}


std::string get_string_from_wcs(const wchar_t* pcs)
{
int res;
char buf[0x400];
char* pbuf = buf;
boost::shared_ptr<char[]> shared_pbuf;


res = WideCharToMultiByte(CP_ACP, 0, pcs, -1, buf, sizeof(buf), NULL, NULL);


if (0 == res && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
res = WideCharToMultiByte(CP_ACP, 0, pcs, -1, NULL, 0, NULL, NULL);


shared_pbuf = boost::shared_ptr<char[]>(new char[res]);


pbuf = shared_pbuf.get();


res = WideCharToMultiByte(CP_ACP, 0, pcs, -1, pbuf, res, NULL, NULL);
}
else if (0 == res)
{
pbuf = "error";
}


return std::string(pbuf);
}
// Embarcadero C++ Builder


// convertion string to wstring
string str1 = "hello";
String str2 = str1;         // typedef UnicodeString String;   -> str2 contains now u"hello";


// convertion wstring to string
String str2 = u"hello";
string str1 = UTF8string(str2).c_str();   // -> str1 contains now "hello"

如果其他人感兴趣的话:我需要一个类,可以在任何stringwstring被期望的地方互换使用。下面的类convertible_string基于dk123的解决方案,可以用stringchar const*wstringwchar_t const*进行初始化,并且可以通过stringwstring赋值或隐式转换为stringwstring(因此可以传递给接受其中任何一个的函数)。

class convertible_string
{
public:
// default ctor
convertible_string()
{}


/* conversion ctors */
convertible_string(std::string const& value) : value_(value)
{}
convertible_string(char const* val_array) : value_(val_array)
{}
convertible_string(std::wstring const& wvalue) : value_(ws2s(wvalue))
{}
convertible_string(wchar_t const* wval_array) : value_(ws2s(std::wstring(wval_array)))
{}


/* assignment operators */
convertible_string& operator=(std::string const& value)
{
value_ = value;
return *this;
}
convertible_string& operator=(std::wstring const& wvalue)
{
value_ = ws2s(wvalue);
return *this;
}


/* implicit conversion operators */
operator std::string() const { return value_; }
operator std::wstring() const { return s2ws(value_); }
private:
std::string value_;
};

这个解决方案受到dk123的解决方案的启发,但使用了一个依赖于地区的codecvt facet。结果是区域编码的字符串而不是UTF-8(如果它没有设置为区域设置):

std::string w2s(const std::wstring &var)
{
static std::locale loc("");
auto &facet = std::use_facet<std::codecvt<wchar_t, char, std::mbstate_t>>(loc);
return std::wstring_convert<std::remove_reference<decltype(facet)>::type, wchar_t>(&facet).to_bytes(var);
}


std::wstring s2w(const std::string &var)
{
static std::locale loc("");
auto &facet = std::use_facet<std::codecvt<wchar_t, char, std::mbstate_t>>(loc);
return std::wstring_convert<std::remove_reference<decltype(facet)>::type, wchar_t>(&facet).from_bytes(var);
}

我一直在找,但我找不到。最后,我发现我可以使用带有正确typename的std::use_facet()函数从std::locale中获得正确的facet。希望这能有所帮助。

#include <boost/locale.hpp>
namespace lcv = boost::locale::conv;


inline std::wstring fromUTF8(const std::string& s)
{ return lcv::utf_to_utf<wchar_t>(s); }


inline std::string toUTF8(const std::wstring& ws)
{ return lcv::utf_to_utf<char>(ws); }

我使用下面的wstring转换为字符串。

std::string strTo;
char *szTo = new char[someParam.length() + 1];
szTo[someParam.size()] = '\0';
WideCharToMultiByte(CP_ACP, 0, someParam.c_str(), -1, szTo, (int)someParam.length(), NULL, NULL);
strTo = szTo;
delete szTo;

默认编码:

  • Windows utf - 16。
  • Linux utf - 8。
  • MacOS utf - 8。

我的解决方案步骤,包括空字符\0(避免截断)。不使用windows.h头文件中的函数:

  1. 添加宏来检测平台。 Windows/Linux和其他
  2. . txt
  1. 创建转换std::wstring为std::string和反向std::string为std::wstring的函数
  1. 创建打印函数
  1. 打印std::string/ std::wstring

检查RawString文字。原始字符串后缀。

Linux的代码。使用std:: cout直接打印std:: string, Linux上的默认编码是UTF-8,不需要额外的函数。

在Windows上,如果你需要打印unicode。我们可以使用WriteConsole从std::wstring中打印unicode字符。

最后在Windows。你需要一个强大和完整的视图支持unicode字符在控制台。 我建议Windows终端

质量保证

  • 用vc++在Microsoft Visual Studio 2019上进行测试;std = c + + 17。(Windows项目)
  • 在repl上测试。它使用Clang编译器;std = c + + 17。
为什么你不使用<codecvt>头函数和类?
A.弃用已移除或弃用的特性不可能在vc++上构建,但在g++上没有问题。我更喜欢零警告和头痛。

Q。 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和Windowsl上的标准数据类型

Q。 std::string是跨平台的?
答:< / >强是的。string使用char元素。Char类型在大多数编译器中保证是相同的字节大小。Char类型大小为1字节。检查UNIX、Linux和Windowsl上的标准数据类型

完整的示例代码


#include <iostream>
#include <set>
#include <string>
#include <locale>


// WINDOWS
#if (_WIN32)
#include <Windows.h>
#include <conio.h>
#define WINDOWS_PLATFORM 1
#define DLLCALL STDCALL
#define DLLIMPORT _declspec(dllimport)
#define DLLEXPORT _declspec(dllexport)
#define DLLPRIVATE
#define NOMINMAX


//EMSCRIPTEN
#elif defined(__EMSCRIPTEN__)
#include <emscripten/emscripten.h>
#include <emscripten/bind.h>
#include <unistd.h>
#include <termios.h>
#define EMSCRIPTEN_PLATFORM 1
#define DLLCALL
#define DLLIMPORT
#define DLLEXPORT __attribute__((visibility("default")))
#define DLLPRIVATE __attribute__((visibility("hidden")))


// LINUX - Ubuntu, Fedora, , Centos, Debian, RedHat
#elif (__LINUX__ || __gnu_linux__ || __linux__ || __linux || linux)
#define LINUX_PLATFORM 1
#include <unistd.h>
#include <termios.h>
#define DLLCALL CDECL
#define DLLIMPORT
#define DLLEXPORT __attribute__((visibility("default")))
#define DLLPRIVATE __attribute__((visibility("hidden")))
#define CoTaskMemAlloc(p) malloc(p)
#define CoTaskMemFree(p) free(p)


//ANDROID
#elif (__ANDROID__ || ANDROID)
#define ANDROID_PLATFORM 1
#define DLLCALL
#define DLLIMPORT
#define DLLEXPORT __attribute__((visibility("default")))
#define DLLPRIVATE __attribute__((visibility("hidden")))


//MACOS
#elif defined(__APPLE__)
#include <unistd.h>
#include <termios.h>
#define DLLCALL
#define DLLIMPORT
#define DLLEXPORT __attribute__((visibility("default")))
#define DLLPRIVATE __attribute__((visibility("hidden")))
#include "TargetConditionals.h"
#if TARGET_OS_IPHONE && TARGET_IPHONE_SIMULATOR
#define IOS_SIMULATOR_PLATFORM 1
#elif TARGET_OS_IPHONE
#define IOS_PLATFORM 1
#elif TARGET_OS_MAC
#define MACOS_PLATFORM 1
#else


#endif


#endif






typedef std::string String;
typedef std::wstring WString;


#define EMPTY_STRING u8""s
#define EMPTY_WSTRING L""s


using namespace std::literals::string_literals;


class Strings
{
public:
static String WideStringToString(const WString& wstr)
{
if (wstr.empty())
{
return String();
}
size_t pos;
size_t begin = 0;
String ret;


#if WINDOWS_PLATFORM
int size;
pos = wstr.find(static_cast<wchar_t>(0), begin);
while (pos != WString::npos && begin < wstr.length())
{
WString segment = WString(&wstr[begin], pos - begin);
size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, &segment[0], segment.size(), NULL, 0, NULL, NULL);
String converted = String(size, 0);
WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, &segment[0], segment.size(), &converted[0], converted.size(), NULL, NULL);
ret.append(converted);
ret.append({ 0 });
begin = pos + 1;
pos = wstr.find(static_cast<wchar_t>(0), begin);
}
if (begin <= wstr.length())
{
WString segment = WString(&wstr[begin], wstr.length() - begin);
size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, &segment[0], segment.size(), NULL, 0, NULL, NULL);
String converted = String(size, 0);
WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, &segment[0], segment.size(), &converted[0], converted.size(), NULL, NULL);
ret.append(converted);
}
#elif LINUX_PLATFORM || MACOS_PLATFORM || EMSCRIPTEN_PLATFORM
size_t size;
pos = wstr.find(static_cast<wchar_t>(0), begin);
while (pos != WString::npos && begin < wstr.length())
{
WString segment = WString(&wstr[begin], pos - begin);
size = wcstombs(nullptr, segment.c_str(), 0);
String converted = 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())
{
WString segment = WString(&wstr[begin], wstr.length() - begin);
size = wcstombs(nullptr, segment.c_str(), 0);
String converted = String(size, 0);
wcstombs(&converted[0], segment.c_str(), converted.size());
ret.append(converted);
}
#else
static_assert(false, "Unknown Platform");
#endif
return ret;
}


static WString StringToWideString(const String& str)
{
if (str.empty())
{
return WString();
}


size_t pos;
size_t begin = 0;
WString ret;
#ifdef WINDOWS_PLATFORM
int size = 0;
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);
size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, &segment[0], segment.size(), &converted[0], converted.length());
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() + 1, 0);
size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, segment.c_str(), segment.size(), &converted[0], converted.length());
converted.resize(size);
ret.append(converted);
}


#elif LINUX_PLATFORM || MACOS_PLATFORM || EMSCRIPTEN_PLATFORM
size_t size;
pos = str.find(static_cast<char>(0), begin);
while (pos != String::npos)
{
String segment = String(&str[begin], pos - begin);
WString converted = 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())
{
String segment = String(&str[begin], str.length() - begin);
WString converted = WString(segment.size(), 0);
size = mbstowcs(&converted[0], &segment[0], converted.size());
converted.resize(size);
ret.append(converted);
}
#else
static_assert(false, "Unknown Platform");
#endif
return ret;
}
};


enum class ConsoleTextStyle
{
DEFAULT = 0,
BOLD = 1,
FAINT = 2,
ITALIC = 3,
UNDERLINE = 4,
SLOW_BLINK = 5,
RAPID_BLINK = 6,
REVERSE = 7,
};


enum class ConsoleForeground
{
DEFAULT = 39,
BLACK = 30,
DARK_RED = 31,
DARK_GREEN = 32,
DARK_YELLOW = 33,
DARK_BLUE = 34,
DARK_MAGENTA = 35,
DARK_CYAN = 36,
GRAY = 37,
DARK_GRAY = 90,
RED = 91,
GREEN = 92,
YELLOW = 93,
BLUE = 94,
MAGENTA = 95,
CYAN = 96,
WHITE = 97
};


enum class ConsoleBackground
{
DEFAULT = 49,
BLACK = 40,
DARK_RED = 41,
DARK_GREEN = 42,
DARK_YELLOW = 43,
DARK_BLUE = 44,
DARK_MAGENTA = 45,
DARK_CYAN = 46,
GRAY = 47,
DARK_GRAY = 100,
RED = 101,
GREEN = 102,
YELLOW = 103,
BLUE = 104,
MAGENTA = 105,
CYAN = 106,
WHITE = 107
};


class Console
{
private:
static void EnableVirtualTermimalProcessing()
{
#if defined WINDOWS_PLATFORM
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD dwMode = 0;
GetConsoleMode(hOut, &dwMode);
if (!(dwMode & ENABLE_VIRTUAL_TERMINAL_PROCESSING))
{
dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
SetConsoleMode(hOut, dwMode);
}
#endif
}


static void ResetTerminalFormat()
{
std::cout << u8"\033[0m";
}


static void SetVirtualTerminalFormat(ConsoleForeground foreground, ConsoleBackground background, std::set<ConsoleTextStyle> styles)
{
String format = u8"\033[";
format.append(std::to_string(static_cast<int>(foreground)));
format.append(u8";");
format.append(std::to_string(static_cast<int>(background)));
if (styles.size() > 0)
{
for (auto it = styles.begin(); it != styles.end(); ++it)
{
format.append(u8";");
format.append(std::to_string(static_cast<int>(*it)));
}
}
format.append(u8"m");
std::cout << format;
}
public:
static void Clear()
{


#ifdef WINDOWS_PLATFORM
std::system(u8"cls");
#elif LINUX_PLATFORM || defined MACOS_PLATFORM
std::system(u8"clear");
#elif EMSCRIPTEN_PLATFORM
emscripten::val::global()["console"].call<void>(u8"clear");
#else
static_assert(false, "Unknown Platform");
#endif
}


static void Write(const String& s, ConsoleForeground foreground = ConsoleForeground::DEFAULT, ConsoleBackground background = ConsoleBackground::DEFAULT, std::set<ConsoleTextStyle> styles = {})
{
#ifndef EMSCRIPTEN_PLATFORM
EnableVirtualTermimalProcessing();
SetVirtualTerminalFormat(foreground, background, styles);
#endif
String str = s;
#ifdef WINDOWS_PLATFORM
WString unicode = Strings::StringToWideString(str);
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), unicode.c_str(), static_cast<DWORD>(unicode.length()), nullptr, nullptr);
#elif defined LINUX_PLATFORM || defined MACOS_PLATFORM || EMSCRIPTEN_PLATFORM
std::cout << str;
#else
static_assert(false, "Unknown Platform");
#endif


#ifndef EMSCRIPTEN_PLATFORM
ResetTerminalFormat();
#endif
}


static void WriteLine(const String& s, ConsoleForeground foreground = ConsoleForeground::DEFAULT, ConsoleBackground background = ConsoleBackground::DEFAULT, std::set<ConsoleTextStyle> styles = {})
{
Write(s, foreground, background, styles);
std::cout << std::endl;
}


static void Write(const WString& s, ConsoleForeground foreground = ConsoleForeground::DEFAULT, ConsoleBackground background = ConsoleBackground::DEFAULT, std::set<ConsoleTextStyle> styles = {})
{
#ifndef EMSCRIPTEN_PLATFORM
EnableVirtualTermimalProcessing();
SetVirtualTerminalFormat(foreground, background, styles);
#endif
WString str = s;


#ifdef WINDOWS_PLATFORM
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), str.c_str(), static_cast<DWORD>(str.length()), nullptr, nullptr);
#elif LINUX_PLATFORM || MACOS_PLATFORM || EMSCRIPTEN_PLATFORM
std::cout << Strings::WideStringToString(str);
#else
static_assert(false, "Unknown Platform");
#endif


#ifndef EMSCRIPTEN_PLATFORM
ResetTerminalFormat();
#endif
}


static void WriteLine(const WString& s, ConsoleForeground foreground = ConsoleForeground::DEFAULT, ConsoleBackground background = ConsoleBackground::DEFAULT, std::set<ConsoleTextStyle> styles = {})
{
Write(s, foreground, background, styles);
std::cout << std::endl;
}


static void WriteLine()
{
std::cout << std::endl;
}


static void Pause()
{
char c;
do
{
c = getchar();
std::cout << "Press Key " << std::endl;
} while (c != 64);
std::cout << "KeyPressed" << std::endl;
}


static int PauseAny(bool printWhenPressed = false, ConsoleForeground foreground = ConsoleForeground::DEFAULT, ConsoleBackground background = ConsoleBackground::DEFAULT, std::set<ConsoleTextStyle> styles = {})
{
int ch;
#ifdef WINDOWS_PLATFORM
ch = _getch();
#elif LINUX_PLATFORM || MACOS_PLATFORM || EMSCRIPTEN_PLATFORM
struct termios oldt, newt;
tcgetattr(STDIN_FILENO, &oldt);
newt = oldt;
newt.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
ch = getchar();
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
#else
static_assert(false, "Unknown Platform");
#endif
if (printWhenPressed)
{
Console::Write(String(1, ch), foreground, background, styles);
}
return ch;
}
};






int main()
{
std::locale::global(std::locale(u8"en_US.UTF8"));
auto str = u8"🐶\0Hello\0🐶123456789也不是可运行的程序123456789日本"s;//
WString wstr = L"🐶\0Hello\0🐶123456789也不是可运行的程序123456789日本"s;
WString wstrResult = Strings::StringToWideString(str);
String strResult = Strings::WideStringToString(wstr);
bool equals1 = wstr == wstrResult;
bool equals2 = str == strResult;


Console::WriteLine(u8"█ Converted Strings printed with Console::WriteLine"s, ConsoleForeground::GREEN);
Console::WriteLine(wstrResult, ConsoleForeground::BLUE);//Printed OK on Windows/Linux.
Console::WriteLine(strResult, ConsoleForeground::BLUE);//Printed OK on Windows/Linux.
    

Console::WriteLine(u8"█ Converted Strings printed with std::cout/std::wcout"s, ConsoleForeground::GREEN);
std::cout << strResult << std::endl;//Printed OK on Linux. BAD on Windows.
std::wcout << wstrResult << std::endl; //Printed BAD on Windows/Linux.
Console::WriteLine();
Console::WriteLine(u8"Press any key to exit"s, ConsoleForeground::DARK_GRAY);
Console::PauseAny();


}

你不能在https://repl.it/@JomaCorpFX/StringToWideStringToString#main.cpp上测试这个代码


* * * *的屏幕截图

使用Windows终端  window终端 < / p > < p >使用cmd / powershell enter image description here < / p > < p > Repl。它捕获
enter image description here < / p >

除了转换类型之外,还应该注意字符串的实际格式。

当为多字节字符集 Visual Studio编译时,Win API假设UTF8(实际上是windows编码,它是windows - 28591) 当为Unicode字符集 Visual studio和Win API编译时,假设UTF16 所以,你必须将字符串从UTF16转换为UTF8格式,而不仅仅是转换为std::string.
当处理多字符格式(如一些非拉丁语言)时,这将是必要的 其思想是确定std::wstring 总是表示UTF16std::string 总是表示use UTF8。< / p > 这不是由编译器强制执行的,这是一个更好的策略。 注意我用来定义UTF16 (l)和UTF8 ()的字符串前缀

要在这两种类型之间进行转换,您应该使用:std::codecvt_utf8_utf16<wchar_t > < / >

#include <string>


#include <codecvt>


int main()
{


std::string original8 = u8"הלו";


std::wstring original16 = L"הלו";


//C++11 format converter
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> convert;


//convert to UTF8 and std::string
std::string utf8NativeString = convert.to_bytes(original16);


std::wstring utf16NativeString = convert.from_bytes(original8);


assert(utf8NativeString == original8);
assert(utf16NativeString == original16);


return 0;
}

我花了很多悲伤的日子,试图为c++ 17找到一种方法来做到这一点,它已经弃用了code_cvt facet,这是我通过组合来自几个不同来源的代码所能想到的最好的方法:

setlocale( LC_ALL, "en_US.UTF-8" ); //Invoked in main()


std::string wideToMultiByte( std::wstring const & wideString )
{
std::string ret;
std::string buff( MB_CUR_MAX, '\0' );


for ( wchar_t const & wc : wideString )
{
int mbCharLen = std::wctomb( &buff[ 0 ], wc );


if ( mbCharLen < 1 ) { break; }


for ( int i = 0; i < mbCharLen; ++i )
{
ret += buff[ i ];
}
}


return ret;
}


std::wstring multiByteToWide( std::string const & multiByteString )
{
std::wstring ws( multiByteString.size(), L' ' );
ws.resize(
std::mbstowcs( &ws[ 0 ],
multiByteString.c_str(),
multiByteString.size() ) );


return ws;
}

我在Windows 10上测试了这段代码,至少就我的目的而言,它似乎运行良好。如果这没有考虑到你可能需要处理的一些疯狂的边缘情况,请不要对我进行私刑,我相信有更多经验的人可以改进这一点!: -)

此外,在该表扬的地方表扬:

适用于wideToMultiByte()

copy for multiByteToWide

如果你正在处理文件路径(当我发现需要wstring-to-string时,我经常这样做),你可以使用文件系统:路径(自c++ 17以来):

#include <filesystem>


const std::wstring wPath = GetPath(); // some function that returns wstring
const std::string path = std::filesystem::path(wPath).string();