BЈо*_*вић 191 c++ unicode stl 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;
}
Run Code Online (Sandbox Code Playgroud)
注释掉的输出是:
std::string = Hello
std::wstring = Hello
std::string = Hello
Run Code Online (Sandbox Code Playgroud)
但不仅仅是:
std::wstring = Hello
Run Code Online (Sandbox Code Playgroud)
这个例子有什么不对吗?我可以像上面那样进行转换吗?
编辑
新的例子(考虑到一些答案)是
#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;
}
Run Code Online (Sandbox Code Playgroud)
输出是:
std::string = Hello
std::wstring = Hello
std::stringstream = 0x860283c
Run Code Online (Sandbox Code Playgroud)
因此stringstream不能用于将wstring转换为字符串.
dk1*_*123 296
正如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 );
Run Code Online (Sandbox Code Playgroud)
wcstombs在遇到这个问题之前,我正在使用内存的繁琐分配/重新分配的组合.
http://en.cppreference.com/w/cpp/locale/wstring_convert
更新(2013年11月28日)
一个衬垫可以这样说(谢谢你Guss的评论):
std::wstring str = std::wstring_convert<std::codecvt_utf8<wchar_t>>().from_bytes("some string");
Run Code Online (Sandbox Code Playgroud)
包装函数可以这样说:(感谢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);
}
Run Code Online (Sandbox Code Playgroud)
注意:关于是否string/ wstring应该作为引用或文字传递给函数存在一些争议(由于C++ 11和编译器更新).我会把决定留给实施者,但值得了解.
注意:我std::codecvt_utf8在上面的代码中使用,但如果您不使用UTF-8,则需要将其更改为您正在使用的相应编码:
http://en.cppreference.com/w/cpp/header/codecvt
nam*_*309 123
解决方案来自: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;
Run Code Online (Sandbox Code Playgroud)
请注意,这里根本没有进行字符集转换.这样做是简单地分配给每个迭代wchar_t的char-一截断转换.它使用std :: string c'tor:
template< class InputIt >
basic_string( InputIt first, InputIt last,
const Allocator& alloc = Allocator() );
Run Code Online (Sandbox Code Playgroud)
如评论中所述:
几乎每个编码中的值0-127都是相同的,因此截断小于127的值会产生相同的文本.放入一个汉字,你会看到失败.
-
Windows代码页1252(Windows英文默认值)的值128-255和unicode的值128-255大致相同,因此如果您使用的那些代码页中的大部分字符应该被截断为正确的值.(我完全希望á和õ能够工作,我知道我们的工作代码依赖于é,我很快就会解决这个问题)
并注意范围的代码点0x80 - 0x9F在Win1252将无法正常工作.这包括€,œ,ž,Ÿ,...
Phi*_*ipp 29
以下是基于其他建议的解决方案:
#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;
}
}
Run Code Online (Sandbox Code Playgroud)
这通常适用于Linux,但会在Windows上产生问题.
小智 11
如果你知道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';
}
Run Code Online (Sandbox Code Playgroud)
这里有实例
Jom*_*oma 11
默认编码:
- Windows UTF-16。
- Linux UTF-8。
- MacOS UTF-8。
我的解决方案步骤,包括空字符 \0 (避免被截断)。不使用 windows.h 头文件上的函数:
- 添加宏来检测平台。 Windows/Linux 和其他
- 创建将 std::wstring 转换为 std::string 并将 std::string 反转为 std::wstring 的函数
- 创建打印功能
- 打印 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 上测试;标准=c++17。(Windows 项目)
- 使用 Clang 编译器在 repl.it 上进行测试;标准=c++17。
问:为什么不使用
<codecvt>头函数和类?
A.弃用 删除或弃用的功能不可能在 VC++ 上构建,但在 g++ 上没有问题。我更喜欢 0 警告和头痛。
问: std ::wstring 是跨平台的吗?
A.否。 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 上的标准数据类型。
问: std ::string 是跨平台的吗?
答:是的。std::string 使用字符元素。在大多数编译器中保证 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\0123456789????????????????????"s;//
WString wstr = L"\0Hello\0123456789????????????????????"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();
}
Run Code Online (Sandbox Code Playgroud)
您无法在https://repl.it/@JomaCorpFX/StringToWideStringToString#main.cpp上测试此代码
我认为官方的方式仍然是深入研究codecvt(你需要某种类似于语言环境的翻译),如同
resultCode = use_facet<codecvt<char, wchar_t, ConversionState> >(locale).
in(stateVar, scratchbuffer, scratchbufferEnd, from, to, toLimit, curPtr);
Run Code Online (Sandbox Code Playgroud)
或类似的东西,我没有工作代码.但我不确定这些天有多少人使用这种机器,有多少人只是要求指向内存,让ICU或其他一些图书馆处理血腥细节.
代码有两个问题:
转换输入const std::string s( ws.begin(), ws.end() );不需要将宽字符正确映射到它们的窄对应物.最有可能的是,每个广泛的角色都会被强制转换char.
这个问题的解决方案已在kem的答案中给出,并涉及narrowlocale的ctypefacet 的功能.
您正在将输出写入两个程序std::cout并std::wcout在同一程序中.二者cout并wcout用相同的流(相关联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;
}
Run Code Online (Sandbox Code Playgroud)如果您正在处理文件路径(当我发现需要 wstring-to-string 时经常这样做),您可以使用filesystem::path (C++17 起):
#include <filesystem>
const std::wstring wPath = GetPath(); // some function that returns wstring
const std::string path = std::filesystem::path(wPath).string();
Run Code Online (Sandbox Code Playgroud)
您也可以直接使用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]);
}
该解决方案受到dk123 解决方案的启发,但使用了依赖于语言环境的 codecvt 方面。结果是区域设置编码字符串而不是 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);
}
Run Code Online (Sandbox Code Playgroud)
我一直在寻找它,但我找不到它。最后我发现我可以通过std::locale使用std::use_facet()具有正确类型名的函数来获得正确的方面。希望这可以帮助。
我花了很多悲伤的日子试图想出一种方法来为 C++17 做到这一点,它已弃用code_cvtFacet,这是我通过组合来自几个不同来源的代码所能想到的最好的方法:
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;
}
Run Code Online (Sandbox Code Playgroud)
我在 Windows 10 上测试了这段代码,至少就我的目的而言,它似乎工作得很好。如果这没有考虑到您可能需要处理的一些疯狂的边缘情况,请不要私刑处死我,我相信有更多经验的人可以对此进行改进!:-)
另外,贷记应得的:
在撰写此答案时,排名第一的Google搜索"convert string 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();
Run Code Online (Sandbox Code Playgroud)
除了只转换类型之外,您还应该注意字符串的实际格式。
编译多字节字符集时, Visual Studio 和 Win API 假定为 UTF8(实际上 Windows 编码为Windows-28591)。
为Unicode 字符集编译时,Visual Studio 和 Win API 假定为 UTF16。
因此,您还必须将字符串从 UTF16 转换为 UTF8 格式,而不仅仅是转换为 std::string。
在使用多字符格式(如某些非拉丁语言)时,这将变得必要。
这个想法是决定std::wstring 总是代表UTF16。
并且std::string 始终代表UTF8。
这不是由编译器强制执行的,它更像是一个很好的策略。请注意我用来定义 UTF16 ( L ) 和 UTF8 ( u8 )的字符串前缀。
要在这两种类型之间进行转换,您应该使用: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;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
256147 次 |
| 最近记录: |