C++ Преобразование строки (или char*) в wstring (или wchar_t*)

string s = "おはよう";
wstring ws = FUNCTION(s, ws);

Как бы я назначил содержимое s для ws?

Искал в Google и использовал некоторые методы, но они не могут назначить точное содержание. Содержание искажено.

20 ответов

Предполагая, что входная строка в вашем примере (おはよう) имеет кодировку UTF-8 (что не так, по внешнему виду, но давайте предположим, что это ради объяснения:-)) представление строки Unicode Если вас интересует, тогда ваша проблема может быть полностью решена только с помощью стандартной библиотеки (C++11 и новее).

Версия TL;DR:

#include <locale>
#include <codecvt>
#include <string>

std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
std::string narrow = converter.to_bytes(wide_utf16_source_string);
std::wstring wide = converter.from_bytes(narrow_utf8_source_string);

Более длинный онлайн компилируемый и запускаемый пример:

(Все они показывают один и тот же пример. Есть только много для избыточности...)

Примечание (старое):

Как указано в комментариях и объяснено в /questions/47607692/naskolko-horosho-unicode-podderzhivaetsya-v-c11/47607703#47607703 существуют случаи, когда использование стандартной библиотеки для преобразования между UTF-8 и UTF-16 может привести к неожиданным различиям в результатах на разных платформах., Для лучшего преобразования, рассмотрим std::codecvt_utf8 как описано на http://en.cppreference.com/w/cpp/locale/codecvt_utf8

Примечание (новое):

Так как codecvt заголовок устарел в C++17, возникли некоторые опасения по поводу решения, представленного в этом ответе. Тем не менее, комитет по стандартам C++ добавил в http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0618r0.html важное заявление

этот библиотечный компонент следует перенести в Приложение D вдоль стороны, пока не будет стандартизирована подходящая замена.

Так что в обозримом будущем codecvt Решение в этом ответе является безопасным и портативным.

int StringToWString(std::wstring &ws, const std::string &s)
{
    std::wstring wsTmp(s.begin(), s.end());

    ws = wsTmp;

    return 0;
}

Ваш вопрос не указан. Строго говоря, этот пример является синтаксической ошибкой. Тем не мение, std::mbstowcs это, вероятно, то, что вы ищете.

Это функция библиотеки C и она работает с буферами, но вот простая в использовании идиома, любезно предоставленная TBohne (ранее Mooing Duck):

std::wstring ws(s.size(), L' '); // Overestimate number of code points.
ws.resize(std::mbstowcs(&ws[0], s.c_str(), s.size())); // Shrink to fit.

Если вы используете Windows/Visual Studio и вам нужно преобразовать строку в wstring, вы можете использовать:

#include <AtlBase.h>
#include <atlconv.h>
...
string s = "some string";
CA2W ca2w(s.c_str());
wstring w = ca2w;
printf("%s = %ls", s.c_str(), w.c_str());

Та же процедура для преобразования wstring в строку (иногда вам нужно будет указать кодовую страницу):

#include <AtlBase.h>
#include <atlconv.h>
...
wstring w = L"some wstring";
CW2A cw2a(w.c_str());
string s = cw2a;
printf("%s = %ls", s.c_str(), w.c_str());

Вы можете указать кодовую страницу и даже UTF8 (это очень хорошо при работе с JNI/Java).

CA2W ca2w(str, CP_UTF8);

Если вы хотите узнать больше о кодовых страницах, то есть интересная статья о Джоэле о программном обеспечении: Абсолютный минимум, который должен знать каждый разработчик программного обеспечения. Об Unicode и наборах символов необходимо знать абсолютно.

Эти макросы CA2W (Convert Ansi to Wide=unicode) являются частью макросов преобразования строк ATL и MFC, включая примеры.

Иногда вам нужно отключить предупреждение безопасности #4995', я не знаю другого обходного пути (для меня это случилось, когда я скомпилировал для WindowsXp в VS2012).

#pragma warning(push)
#pragma warning(disable: 4995)
#include <AtlBase.h>
#include <atlconv.h>
#pragma warning(pop)

Редактировать: Ну, в соответствии с этой статьей статья Джоэля выглядит так: "В то время как развлекательный, он довольно легкий на реальных технических деталях". Статья: Что каждый программист абсолютно, положительно должен знать о кодировании и наборах символов для работы с текстом.

Вот способ объединения 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();

Только для Windows API, до C++11, если кому-то это нужно:

#include <stdexcept>
#include <vector>
#include <windows.h>

using std::runtime_error;
using std::string;
using std::vector;
using std::wstring;

wstring utf8toUtf16(const string & str)
{
   if (str.empty())
      return wstring();

   size_t charsNeeded = ::MultiByteToWideChar(CP_UTF8, 0, 
      str.data(), (int)str.size(), NULL, 0);
   if (charsNeeded == 0)
      throw runtime_error("Failed converting UTF-8 string to UTF-16");

   vector<wchar_t> buffer(charsNeeded);
   int charsConverted = ::MultiByteToWideChar(CP_UTF8, 0, 
      str.data(), (int)str.size(), &buffer[0], buffer.size());
   if (charsConverted == 0)
      throw runtime_error("Failed converting UTF-8 string to UTF-16");

   return wstring(&buffer[0], charsConverted);
}

От char* в wstring:

char* str = "hello worlddd";
wstring wstr (str, str+strlen(str));

От string в wstring:

string str = "hello worlddd";
wstring wstr (str.begin(), str.end());

Обратите внимание, что это работает только в том случае, если преобразуемая строка содержит только символы ASCII.

Этот вариант мой любимый в реальной жизни. Он преобразует входные данные, если это действительно UTF-8, в соответствующие wstring, Если вход поврежден, wstring построен из отдельных байтов. Это очень полезно, если вы не можете быть уверены в качестве входных данных.

std::wstring convert(const std::string& input)
{
    try
    {
        std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
        return converter.from_bytes(input);
    }
    catch(std::range_error& e)
    {
        size_t length = input.length();
        std::wstring result;
        result.reserve(length);
        for(size_t i = 0; i < length; i++)
        {
            result.push_back(input[i] & 0xFF);
        }
        return result;
    }
}

Используя Boost.Locale:

ws = boost::locale::conv::utf_to_utf<wchar_t>(s);

Вы можете использовать путь ускорения или стандартный путь; что намного проще. путь ускорения проще для кроссплатформенного приложения

      #include <boost/filesystem/path.hpp>

namespace fs = boost::filesystem;

//s to w
std::string s = "xxx";
auto w = fs::path(s).wstring();

//w to s
std::wstring w = L"xxx";
auto s = fs::path(w).string();

если вам нравится использовать std:

      #include <filesystem>
namespace fs = std::filesystem;

//The same

c ++ более старая версия

      #include <experimental/filesystem>
namespace fs = std::experimental::filesystem;

//The same

Код внутри по-прежнему реализует преобразователь, который вам не нужно распутывать.

Для меня самый несложный вариант без больших накладных расходов:

Включают:

      #include <atlbase.h>
#include <atlconv.h>

Конвертировать:

      char* whatever = "test1234";
std::wstring lwhatever = std::wstring(CA2W(std::string(whatever).c_str()));

Если нужно:

      lwhatever.c_str();

Строка в строку

std::wstring Str2Wstr(const std::string& str)
{
    int size_needed = MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0);
    std::wstring wstrTo(size_needed, 0);
    MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), &wstrTo[0], size_needed);
    return wstrTo;
}

wstring to String

std::string Wstr2Str(const std::wstring& wstr)
{
    typedef std::codecvt_utf8<wchar_t> convert_typeX;
    std::wstring_convert<convert_typeX, wchar_t> converterX;
    return converterX.to_bytes(wstr);
}

Если у вас есть QT и вам лень реализовывать функцию и прочее, вы можете использовать

std::string str; QString(ул).toStdWString()

Вот мое супер базовое решение, которое может не сработать для всех. Но сработает для многих.

Это требует использования библиотеки поддержки рекомендаций. Это довольно официальная библиотека C ++, разработанная многими авторами комитетов C ++:

          std::string to_string(std::wstring const & wStr)
    {
        std::string temp = {};

        for (wchar_t const & wCh : wStr)
        {
            // If the string can't be converted gsl::narrow will throw
            temp.push_back(gsl::narrow<char>(wCh));
        }

        return temp;
    }

Все, что я делаю, - это разрешить преобразование, если это возможно. В противном случае выбросить исключение.

Через использование gsl :: thin (https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#es49-if-you-must-use-a-cast-use-a- named-cast )

std::string -> wchar_t[] с безопасной функцией mbstowcs_s:

авто ws = std:: make_unique(s.size () + 1);
mbstowcs_s (nullptr, ws.get (), s.size() + 1, s.c_str(), s.size());

Это из моего примера кода

реализация utf-8

Предполагая, что вашstd::stringимеет кодировку utf8, это независимая от платформы реализация функций преобразования wstring-string:

      #include <codecvt>
#include <codecvt>
#include <string>
#include <type_traits>

std::string wstring_to_utf8(std::wstring const& str)
{
  std::wstring_convert<std::conditional_t<
        sizeof(wchar_t) == 4,
        std::codecvt_utf8<wchar_t>,
        std::codecvt_utf8_utf16<wchar_t>>> converter;
  return converter.to_bytes(str);
}

std::wstring utf8_to_wstring(std::string const& str)
{
  std::wstring_convert<std::conditional_t<
        sizeof(wchar_t) == 4,
        std::codecvt_utf8<wchar_t>,
        std::codecvt_utf8_utf16<wchar_t>>> converter;
  return converter.from_bytes(str);
}

получивший наибольшее количество голосов на данный момент , выглядит аналогично, но дает неправильные результаты для символов, отличных от BMP (например, Emojis), на платформах, отличных от Windows.wchar_tэто UTF-16 в Windows, но везде UTF-32. std::conditionalзаботится об этом различии.

Предупреждение об устаревании MSVC

В msvc это может привести к появлению предупреждений об устаревании. Вы можете отключить их, обернув функции в

      #pragma warning(push)
#pragma warning(disable : 4996)
<the two functions>
#pragma warning(pop)

Ответ,Ответ Иоганна Герелла объясняет, почему можно отключить это предупреждение.

Получение utf-8 на msvc

Обратите внимание: когда вы пишете в исходном коде обычную строку (например,std::string s = "おはよう";), по умолчанию в msvc он не будет закодирован в формате utf-8. Я настоятельно рекомендую установить для вашего набора символов msvc значение utf-8 для решения этой проблемы: https://learn.microsoft.com/en-us/cpp/build/reference/utf-8-set-source-and-executable-character-sets-to-utf-8?view=msvc-170

Метод s2ws работает хорошо. Надежда помогает.

std::wstring s2ws(const std::string& s) {
    std::string curLocale = setlocale(LC_ALL, ""); 
    const char* _Source = s.c_str();
    size_t _Dsize = mbstowcs(NULL, _Source, 0) + 1;
    wchar_t *_Dest = new wchar_t[_Dsize];
    wmemset(_Dest, 0, _Dsize);
    mbstowcs(_Dest,_Source,_Dsize);
    std::wstring result = _Dest;
    delete []_Dest;
    setlocale(LC_ALL, curLocale.c_str());
    return result;
}

Основываясь на моем собственном тестировании (на Windows 8, vs2010), mbstowcs может действительно повредить исходную строку, она работает только с кодовой страницей ANSI. Если MultiByteToWideChar/WideCharToMultiByte также может привести к повреждению строки - но они, как правило, заменяют символы, которые они не знают, на "?" вопросительные знаки, но mbstowcs имеет тенденцию останавливаться, когда встречает неизвестный символ и обрезает строку в этой самой точке. (Я проверил вьетнамские символы на финских окнах).

Так что предпочтите Multi*-Windows API-функции по сравнению с аналоговыми и C-функциями.

Кроме того, я заметил, что самый короткий способ кодирования строки из одной кодовой страницы в другую - это не вызовы функций API MultiByteToWideChar/WideCharToMultiByte, а их аналоговые макросы ATL: W2A / A2W.

Таким образом, аналоговая функция, как упомянуто выше, звучит так:

wstring utf8toUtf16(const string & str)
{
   USES_CONVERSION;
   _acp = CP_UTF8;
   return A2W( str.c_str() );
}

_acp объявлен в макросе USES_CONVERSION.

Или также функцию, которую я часто упускаю при выполнении преобразования старых данных в новые:

string ansi2utf8( const string& s )
{
   USES_CONVERSION;
   _acp = CP_ACP;
   wchar_t* pw = A2W( s.c_str() );

   _acp = CP_UTF8;
   return W2A( pw );
}

Но обратите внимание, что эти макросы используют большой стек - не используйте для циклов или рекурсивных циклов для одной и той же функции - после использования макроса W2A или A2W - лучше вернуть ASAP, поэтому стек будет освобожден от временного преобразования.

string s = "おはよう"; это ошибка.

Вы должны использовать wstring напрямую:

wstring ws = L"おはよう";

Используйте этот код для преобразования вашей строки в wstring

std::wstring string2wString(const std::string& s){
    int len;
    int slength = (int)s.length() + 1;
    len = MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, 0, 0); 
    wchar_t* buf = new wchar_t[len];
    MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, buf, len);
    std::wstring r(buf);
    delete[] buf;
    return r;
}

int main(){
    std::wstring str="your string";
    std::wstring wStr=string2wString(str);
    return 0;
}
Другие вопросы по тегам