Как преобразовать wstring в строку?
вопрос в том, как преобразовать wstring в string?
у меня есть следующий пример :
#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
но не только :
std::wstring = Hello
что-нибудь не так в Примере? Могу ли я сделать преобразование, как указано выше?
EDIT
новый пример (с учетом некоторых ответов) - это
#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.
15 ответов:
вот разработанное решение, основанное на других предложениях:
#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.
как указал Кубби в одном из комментариев,
std::wstring_convert(C++11) обеспечивает аккуратное простое решение (вам нужно#include<locale>и<codecvt>):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 за ваш комментарий)
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); } 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://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;
будьте осторожны что есть нет преобразование набора символов происходит здесь вообще. Что это делает, это просто назначить каждый повторенный
wchar_tдоchar- преобразование усек. Он использует std:: string c'Tor:template< class InputIt > basic_string( InputIt first, InputIt last, const Allocator& alloc = Allocator() );как указано в комментариях:
значения 0-127 идентичны практически в каждой кодировке, поэтому усечение значения, которые все меньше 127, приводят к одному и тому же тексту. Положить в китайский иероглиф и вы увидите провал.
-
значения 128-255 кодовой страницы windows 1252 (Windows English по умолчанию) и значения 128-255 юникода в основном совпадают, так что если это кодовая страница, которую вы используете, большинство из этих символов должны быть усекается до правильных значений. (Я полностью ожидал, что á и õ будут работать, Я знаю, что наш код на работе полагается на это для é, который я скоро исправлю)
и обратите внимание, что кодовые точки в диапазоне
0x80 - 0x9Fна Win1252 будет не работа. Это включает в себя€,œ,ž,Ÿ, ...
вместо того, чтобы включать локаль и все эти причудливые вещи, если вы знаете, что ваша строка конвертируется, просто сделайте это:
видео здесь#include <iostream> #include <string> using namespace std; int main() { wstring w(L"bla"); string result; for(char x : w) result += x; cout << result << '\n'; }
Я считаю, что официальный путь все еще идти thorugh
codecvtфасеты (вам нужен какой-то перевод с учетом локали), как вresultCode = use_facet<codecvt<char, wchar_t, ConversionState> >(locale). in(stateVar, scratchbuffer, scratchbufferEnd, from, to, toLimit, curPtr);или что-то в этом роде, у меня нет рабочего кода, лежащего вокруг. Но я не уверен, сколько людей в наши дни используют этот механизм, а сколько просто просят указатели на память и позволяют ICU или какой-либо другой библиотеке обрабатывать кровавые детали.
вы можете также просто использовать узкий метод фасета ctype напрямую:
#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]); }
на момент написания этого ответа поиск google номер один для" convert string wstring " приведет вас на эту страницу. Мой ответ показывает, как преобразовать строку в wstring, хотя это не фактический вопрос, и я, вероятно, должен удалить этот ответ, но это считается плохой формой. вы можете перейти к этот ответ StackOverflow, который теперь занимает более высокое место, чем эта страница.
вот способ объединения string, 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();
есть две проблемы с кодом:
конверсия в
const std::string s( ws.begin(), ws.end() );не требуется правильно сопоставлять широкие символы с их узким аналогом. Скорее всего, каждый символ будет преобразован тип кchar.
Решение этой проблемы уже дано в ответ Кемь и включает в себяnarrowфункция локалиctypeаспект.вы пишете вывод для обоих
std::coutиstd::wcoutв той же программе. Обаcoutиwcoutсвязаны с одним и тем же потоком (stdout) и результаты использования одного и того же потока как байт-ориентированного потока (какcoutделает) и широко ориентированный поток (какwcoutdoes) не определены.
Лучший вариант-избегать смешивания узкого и широкого выхода в один и тот же (базовый) поток. Ибо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; }
в моем случае я должен использовать многобайтовый символ (MBCS), и я хочу использовать std::string и std::wstring. И не может использовать c++11. Поэтому я использую mbstowcs и wcstombs.
Я делаю ту же функцию с помощью new, delete [], но это медленнее, чем это.
Это может помочь преобразование между различными типами строк
EDIT
однако, в случае преобразования в 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); }EDIT использовать менее 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); }
это решение вдохновлено решением dk123, но использует зависящий от локали аспект codecvt. Результат находится в кодированной строке locale вместо utf8 (если он не установлен как locale):
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); }Я искал его, но не могу найти. Наконец я обнаружил, что могу получить правильный фасет из std::locale с помощью функции std::use_facet() с правильным именем типа. Надеюсь, это поможет.
в случае, если кто-то еще заинтересован: мне нужен был класс, который мог бы использоваться взаимозаменяемо везде, где либо
stringили . Следующий классconvertible_stringна основе решение dk123, может быть инициализирован сstring,char const*,wstringилиwchar_t const*и может быть присвоено или неявно преобразовано в Astringилиwstring(так можно передавать в функции, которые принимают либо).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_; };
#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); }
кодировка по умолчанию на:
- Windows UTF-16.
- Linux UTF-8.
- MacOS UTF-8.
этот код имеет две формы для преобразования std::string в std::wstring и std::wstring в std:: string. Если вы отрицаете #if определенный WIN32, вы получаете тот же результат.
1. std:: string to std:: wstring
*MultiByteToWideChar WinAPI
#if defined WIN32 #include <windows.h> #endif std::wstring StringToWideString(std::string str) { if (str.empty()) { return std::wstring(); } size_t len = str.length() + 1; std::wstring ret = std::wstring(len, 0); #if defined WIN32 int size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, &str[0], str.size(), &ret[0], len); ret.resize(size); #else size_t size = 0; _locale_t lc = _create_locale(LC_ALL, "en_US.UTF-8"); errno_t retval = _mbstowcs_s_l(&size, &ret[0], len, &str[0], _TRUNCATE, lc); _free_locale(lc); ret.resize(size - 1); #endif return ret; }2. std:: wstring to std:: string
*WideCharToMultiByte WinAPI
std::string WidestringToString(std::wstring wstr) { if (wstr.empty()) { return std::string(); } #if defined WIN32 int size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, &wstr[0], wstr.size(), NULL, 0, NULL, NULL); std::string ret = std::string(size, 0); WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, &wstr[0], wstr.size(), &ret[0], size, NULL, NULL); #else size_t size = 0; _locale_t lc = _create_locale(LC_ALL, "en_US.UTF-8"); errno_t err = _wcstombs_s_l(&size, NULL, 0, &wstr[0], _TRUNCATE, lc); std::string ret = std::string(size, 0); err = _wcstombs_s_l(&size, &ret[0], size, &wstr[0], _TRUNCATE, lc); _free_locale(lc); ret.resize(size - 1); #endif return ret; }3. В windows вам нужно распечатать unicode, используя WinAPI.
#if defined _WIN32 void WriteLineUnicode(std::string s) { std::wstring unicode = StringToWideString(s); WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), unicode.c_str(), unicode.length(), NULL, NULL); std::cout << std::endl; } void WriteUnicode(std::string s) { std::wstring unicode = StringToWideString(s); WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), unicode.c_str(), unicode.length(), NULL, NULL); } void WriteLineUnicode(std::wstring ws) { WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), ws.c_str(), ws.length(), NULL, NULL); std::cout << std::endl; } void WriteUnicode(std::wstring ws) { WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), ws.c_str(), ws.length(), NULL, NULL); }4. По основной программе.
#if defined _WIN32 int wmain(int argc, WCHAR ** args) #else int main(int argc, CHAR ** args) #endif { std::string source = u8"ÜüΩωЙ你月曜日\naèéøÞǽлљΣæča"; std::wstring wsource = L"ÜüΩωЙ你月曜日\naèéøÞǽлљΣæča"; WriteLineUnicode(L"@" + StringToWideString(source) + L"@"); WriteLineUnicode("@" + WidestringToString(wsource) + "@"); return EXIT_SUCCESS; }5. Наконец-то вам нужен мощная и полная поддержка символов Юникода в консоли. Я рекомендую ConEmu и терминал по умолчанию на Windows. Вам нужно подключить Visual Studio к ConEmu. Помните, что exe-файл Visual Studio является devenv.exe
протестировано в Visual Studio 2017 с VC++; std=c++17.
результат
Я использую ниже, чтобы преобразовать wstring в string.
std::string strTo; char *szTo = new char[someParam.length() + 1]; szTo[someParam.size()] = ''; WideCharToMultiByte(CP_ACP, 0, someParam.c_str(), -1, szTo, (int)someParam.length(), NULL, NULL); strTo = szTo; delete szTo;
// 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"

Comments