Как преобразовать wstring в const char * в C ++ 17? [Дубликат]

A ListIterator позволяет добавлять или удалять элементы в списке. Предположим, у вас есть список объектов Car:

List<Car> cars = ArrayList<>();
// add cars here...

for (ListIterator<Car> carIterator = cars.listIterator();  carIterator.hasNext(); )
{
   if (<some-condition>)
   { 
      carIterator().remove()
   }
   else if (<some-other-condition>)
   { 
      carIterator().add(aNewCar);
   }
}
167
задан jleahy 7 March 2013 в 19:56
поделиться

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.

28
ответ дан Philipp 18 August 2018 в 20:00
поделиться
  • 1
    @Phillip: какая часть кода зависит от c-locale? действительно ли нужен std::setlocale(LC_ALL, "");? – smerlin 26 January 2011 в 15:44
  • 2
    использование std::wcout.imbue(locale) должно также выполнять эту работу, и оно имеет то преимущество, что оно не изменяет никакого глобального состояния. – smerlin 26 January 2011 в 16:22
  • 3
    std::wstring_convert из C ++ 11 покрывает много этого шума. – Cubbi 27 September 2011 в 20:34
  • 4
    @Philipp, что вы имеете в виду & quot; будет создавать проблемы в Windows & quot ;? Какие проблемы? – Gili 23 November 2011 в 23:45
  • 5
    Вышеприведенный код дает (как скопирован) дает мне *** glibc detected *** test: malloc(): smallbin double linked list corrupted: 0x000000000180ea30 *** на 64-разрядном Linux (gcc 4.7.3). Кто-нибудь еще испытывает это? – hogliux 10 November 2013 в 14:22

Как заметил Кубби в одном из комментариев, 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

update (2013.11.28)

Один лайнер может быть указан так (спасибо Guss за ваш комментарий):

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

Функции Wrapper могут быть указаны следующим образом: (Спасибо 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://en.cppreference.com/w/cpp/header/codecvt

235
ответ дан Alessandro Jacopson 18 August 2018 в 20:00
поделиться
  • 1
    Пожалуйста, +1 : это официальный стандарт C ++ для преобразования строк. Вы также можете использовать from_bytes для преобразования в другую сторону. Потому что мне лично нравятся однострочники, вот моя версия: std::wstring str = std::wstring_convert<std::codecvt_utf<wchar_t>>().from_bytes("some string"); – Guss 11 November 2013 в 14:59
  • 2
    2 недели я провел с использованием гигантских хитроумных шаблонных монстров, прежде чем я наткнулся на это. Спасибо . Пожалуйста, рассмотрите возможность переноса в простой функции std::string ws2s(std::wstring const&), чтобы получить больше голосов. – quant 13 November 2013 в 08:05
  • 3
    это сработало для меня !!! – richardtk_1 19 July 2014 в 20:34
  • 4
    Похоже, ru.cppreference.com/w/cpp/header/codecvt недоступен в g ++ 4.8.2. Два метода s2ws и ws2s в настоящее время не работают в Linux – Begui 10 September 2014 в 12:34
  • 5
    @RoiDanton: это еще хуже: вы используете кодировку, которая несовместима с вашей конфигурацией компилятора, иначе результат будет таким же, как u8"" (но менее переносимым). Примечание: вам не нужно кодировать исходный код , чтобы быть utf-8, чтобы использовать u8"" - ответственность компилятора заключается в том, чтобы преобразовать из кодировки исходного кода в utf-8, т. Е. , кодировка, используемая для строк в исполняемом файле, может отличаться от кодировки исходного кода (u8"" = source_bytes.decode(source_code_encoding).encode('utf-8'); "" = source_bytes.decode(source_code_encoding).encode(exec_charset)). – jfs 2 May 2017 в 11:42
  • 6

Я считаю, что официальный путь по-прежнему должен идти в сторону codecvt граней (вам нужен какой-то перевод, ориентированный на языковой стандарт), как в

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

или что-то в этом роде, я не есть рабочий код, лежащий вокруг. Но я не уверен, сколько людей в эти дни используют эту технику, и сколько попросят указать указатели на память, и пусть ICU или другая библиотека обрабатывают детали gory.

7
ответ дан Christopher Creutzig 18 August 2018 в 20:00
поделиться

В случае, если кому-то интересен: мне нужен класс, который мог бы использоваться взаимозаменяемо везде, где ожидались string или wstring. Следующий класс convertible_string, основанный на решении dk123 , может быть инициализирован либо с помощью string, char const*, wstring, либо wchar_t const* и может быть назначен или неявно преобразован в либо string или 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_;
};
6
ответ дан Community 18 August 2018 в 20:00
поделиться
  • 1
    Да, это устраняет проблему с использованием cout и wcout. – BЈовић 26 January 2011 в 17:21
  • 2
    Это не wstring для преобразования строк – poitroae 6 September 2012 в 13:09
  • 3
    @ Майкл. Не могли бы вы объяснить? Что относительно этого неверно? Ваш комментарий не поможет без каких-либо подробностей. – Nate 3 October 2012 в 21:48
  • 4
    это строка для преобразования wstring. т.е. противоположность вопроса. – Jeff McClintock 1 February 2017 в 23:24
#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); }
0
ответ дан deep125 18 August 2018 в 20:00
поделиться

В моем случае я должен использовать многобайтовый символ (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);
}
3
ответ дан heon 18 August 2018 в 20:00
поделиться
  • 1
    Как я могу использовать wcstombs_s & quot; с gcc 4.8? Потому что я вижу, что это C ++ 11. – cristian 9 June 2016 в 15:07
  • 2
    @cristian Вы можете использовать & quot; небезопасные & quot; версия этой функции wcstombs() . – Vizor 9 November 2017 в 11:01

Я использую ниже, чтобы преобразовать 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;
-1
ответ дан impulse 18 August 2018 в 20:00
поделиться
  • 1
    Кажется, у вас отсутствует стандартный заголовок (<string>), а определение для WideCharToMultiByte() - это какая-то оболочка вокруг std::wctomb()? – Toby Speight 5 April 2018 в 13:39

Вы можете просто использовать узкий метод ctype facet:

#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]);
}
6
ответ дан legalize 18 August 2018 в 20:00
поделиться

Решение от: 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;

] Остерегайтесь того, что здесь есть no преобразование набора символов. Это просто означает, что каждый итерированный 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 будет работать не . Это включает в себя , œ, ž, Ÿ, ...

111
ответ дан Martin Ba 18 August 2018 в 20:00
поделиться
  • 1
    Как это ни странно, это работает на Visual Studio 10. Что происходит? Это должно привести к усечению привязки от wchar_t к char для всех элементов исходной строки. – Pedro Lamarão 4 January 2013 в 19:41
  • 2
    он не работает на GCC, MacOS. – JavaRunner 31 May 2013 в 22:02
  • 3
    ... когда он переходит к любым нелатинским символам. – JavaRunner 31 May 2013 в 22:14
  • 4
    @ PedroLamarão: значения 0-127 идентичны практически для каждой кодировки, поэтому усекающие значения, которые все меньше 127, дают один и тот же текст. Поместите китайского персонажа, и вы увидите провал. – Mooing Duck 4 September 2013 в 21:20
  • 5
    @ PedroLamarão: значения 128-255 кодовой страницы Windows 1252 (по умолчанию Windows English по умолчанию) и значения 128-255 юникода - это в основном то же самое, поэтому, если это кодовая страница, использующая большинство этих символов должны быть усечены до правильных значений. (Я полностью ожидал, что я и õ работаю, я знаю, что наш код на работе опирается на это для é, который я скоро исправлю) – Mooing Duck 5 September 2013 в 17:30
// 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"
-2
ответ дан necips 18 August 2018 в 20:00
поделиться
  • 1
    объясните, что вы там делаете в своем ответе, иначе он может быть удален – CodeFanatic 11 November 2014 в 13:32
  • 2
    Откуда возникает функция UTF8string? – Jean-Christophe Blanchard 16 March 2016 в 21:27

Вместо того, чтобы включать язык и все эти причудливые вещи, если вы знаете 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';
}

Пример в реальном времени здесь

11
ответ дан rubenvb 18 August 2018 в 20:00
поделиться
  • 1
    +1, потому что это простое решение, которое работает для некоторых сценариев (для свободного определения «works», я мог бы добавить). – raven 14 August 2012 в 10:43
  • 2
    Почти то же самое, что и решение namar0x0309, которое намного элегантнее ИМХО. Но это только я. – onitake 17 June 2013 в 14:57
  • 3
    Я высмеял ваш код, чтобы на самом деле работать с минимальными изменениями ;-) – rubenvb 22 August 2013 в 09:05
  • 4
    -1 Если у вас есть wstring, вероятно, вы имеете дело с многобайтными символами. Если бы вы знали, что строка тривиально конвертируема, вы не будете обрабатывать wstring в первую очередь. Скорее всего, вы имеете дело с другой библиотекой, которая ожидает, что вы правильно обрабатываете wstring. Усечение wchars - это просто попрошайничество, чтобы проследить ошибку позже. Кроме того, вы должны использовать «строковый результат» (w.begin (), w.end ()); если вы собираетесь это сделать, чтобы избежать цикла, который может вызвать много перераспределений. – Kian 22 May 2014 в 20:35

Это решение является вдохновенным решением dk123, но использует языковой зависимый кодекс decec. Результат - в строках, закодированных в локали вместо 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 () с правильным именем. Надеюсь, это поможет.

2
ответ дан Vizor 18 August 2018 в 20:00
поделиться
6
ответ дан Community 7 September 2018 в 04:10
поделиться
6
ответ дан Community 30 October 2018 в 08:18
поделиться
0
ответ дан Joma 30 October 2018 в 08:18
поделиться
Другие вопросы по тегам:

Похожие вопросы: