Jak przekonwertować ciąg na ciąg?

204

Pytanie brzmi: jak przekonwertować ciąg na ciąg?

Mam następny przykład:

#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;
}

wyjście z zakomentowanym wierszem to:

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

ale bez jest tylko:

std::wstring =    Hello

Czy coś jest nie tak w tym przykładzie? Czy mogę wykonać konwersję jak wyżej?

EDYTOWAĆ

Nowym przykładem (biorąc pod uwagę niektóre odpowiedzi) jest

#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;
}

Dane wyjściowe to:

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

dlatego strumienia nie można użyć do konwersji ciągu na łańcuch.

BЈовић
źródło
4
Jak możesz zadać to pytanie, nie określając również kodowania?
David Heffernan
5
@tenfour: Po std::wstringco w ogóle korzystać? stackoverflow.com/questions/1049947/…
dal
11
@dalle Jeśli masz dane, które są już zakodowane za pomocą UTF-16, to czy UTF-16 jest uważane za szkodliwe, jest nieco dyskusyjne. I za to, co jest warte, nie sądzę, aby jakakolwiek forma transformacji była szkodliwa; szkodliwe jest to, że ludzie myślą, że rozumieją Unicode, podczas gdy w rzeczywistości tego nie robią.
David Heffernan
2
Czy musi to być rozwiązanie wieloplatformowe?
ali_bahoo
2
Standard @dalle c ++ nie wspomina w żaden sposób o utf (utf-8 lub utf-16). Masz link, z którego wynika, dlaczego utf-16 nie może być zakodowany za pomocą wstring?
BЈовић

Odpowiedzi:

31

Oto wypracowane rozwiązanie oparte na innych sugestiach:

#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;
  }
}

Zwykle będzie to działać w systemie Linux, ale spowoduje problemy w systemie Windows.

Philipp
źródło
@Phillip: która część kodu zależy od ustawień regionalnych c? czy std::setlocale(LC_ALL, "");naprawdę jest potrzebny?
smerlin
2
używanie std::wcout.imbue(locale)powinno również wykonać zadanie i ma tę zaletę, że nie zmienia żadnego stanu globalnego.
smerlin
32
Z std::wstring_convertC ++ 11 podsumowuje dużo tego hałasu.
Cubbi
7
@Philipp, co masz na myśli mówiąc „spowoduje problemy w systemie Windows”? Jakiego rodzaju problemy?
Gili
1
Powyższy kod daje (jako skopiowany) daje mi *** glibc detected *** test: malloc(): smallbin double linked list corrupted: 0x000000000180ea30 ***na Linuksie 64-bit (gcc 4.7.3). Czy ktoś jeszcze tego doświadcza?
hogliux,
312

Jak zauważył Cubbi w jednym z komentarzy, std::wstring_convert(C ++ 11) zapewnia schludne proste rozwiązanie (musisz #include <locale>i <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 );

wcstombsZanim się z tym spotkałem, korzystałem z kombinacji żmudnego przydzielania / zwalniania pamięci.

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

aktualizacja (2013.11.28)

Jeden linijka może być podana jako tak (Dziękuję Guss za komentarz):

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

Funkcje otoki można określić w następujący sposób: (Dziękujemy ArmanSchwarz za komentarz)

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);
}

Uwaga: istnieją pewne kontrowersje, czy string/ wstringpowinny być przekazywane do funkcji jako odniesienia lub jako literały (ze względu na C ++ 11 i kompilatora aktualizacji). Decyzję pozostawię osobie wdrażającej, ale warto o tym wiedzieć.

Uwaga: używam std::codecvt_utf8powyższego kodu, ale jeśli nie używasz UTF-8, musisz zmienić to na odpowiednie kodowanie:

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

dk123
źródło
25
Proszę +1 : jest to oficjalny standardowy sposób konwersji napisów w C ++. Możesz także użyć from_bytes do konwersji w inny sposób. Ponieważ osobiście lubię jedynki, oto moja wersja:std::wstring str = std::wstring_convert<std::codecvt_utf<wchar_t>>().from_bytes("some string");
Guss,
7
Wygląda na to, że en.cppreference.com/w/cpp/header/codecvt nie jest dostępny od wersji g ++ 4.8.2. Dwie metody s2ws i ws2s nie działają obecnie w systemie Linux
Begui
5
Wygląda na to, że jest to przestarzałe ( stackoverflow.com/a/42946556/211176 ). Mój kompilator zgłasza błędy, gdy próbuję uruchomić ten kod
adam_0
5
Wszystkim, którzy martwią się o C ++ 17 i dalszą kompatybilność (z powodu wycofania) zobacz: stackoverflow.com/a/18597384/6205379
Timo
128

Rozwiązanie z: 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;

Uważaj, że w ogóle nie ma tu miejsca konwersja zestawu znaków. To po prostu przypisuje każdą iterację wchar_tdo char- obciętej konwersji. Używa std :: string c'tor :

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

Jak stwierdzono w komentarzach:

wartości 0-127 są identyczne w praktycznie każdym kodowaniu, więc obcięcie wartości, które są mniejsze niż 127, daje ten sam tekst. Wprowadź chińską postać, a zobaczysz niepowodzenie.

-

wartości 128-255 strony kodowej Windows 1252 (domyślnie Windows English) i wartości 128-255 Unicode są w większości takie same, więc jeśli to jest strona kodowa, której używasz, większość tych znaków powinna zostać obcięta do prawidłowych wartości. (Całkowicie spodziewałem się, że á i õ zadziałają, wiem, że nasz kod działa w oparciu o to dla é, które wkrótce naprawię)

I pamiętaj, że punkty kodowe z zakresu 0x80 - 0x9Fw Win1252 nie będą działać. Obejmuje to , œ, ž, Ÿ, ...

namar0x0309
źródło
2
Dziwnie, to działa w Visual Studio 10. Co się dzieje? Powinno to spowodować obcięcie przypisania z wchar_t do char dla wszystkich elementów oryginalnego łańcucha.
Pedro Lamarão,
6
... jeśli chodzi o dowolne postacie niełacińskie.
JavaRunner
8
@ PedroLamarão: wartości 0-127 są identyczne w praktycznie każdym kodowaniu, więc obcięcie wartości mniejszych niż 127 daje ten sam tekst. Wprowadź chińską postać, a zobaczysz niepowodzenie.
Mooing Duck
3
@ PedroLamarão: wartości 128-255 strony kodowej Windows 1252 (domyślnie Windows English) i wartości 128-255 Unicode są w większości takie same, więc jeśli to jest strona kodowa, której używasz, większość tych znaków powinna zostać obcięta wartości. (Całkowicie spodziewałem się, że á i õ zadziałają, wiem, że nasz kod w pracy opiera się na tym dla é, które wkrótce naprawię)
Mooing Duck
2
To działa świetnie. MSVS 2015 i MSVS 2017 oraz MINGW / g ++ i clang ++. Legit ++ 1.
Nikos
11

Zamiast uwzględniać ustawienia regionalne i wszystkie inne wymyślne rzeczy, jeśli znasz FACT, łańcuch można konwertować, po prostu zrób to:

#include <iostream>
#include <string>

using namespace std;

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

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

Przykład na żywo tutaj

rubenvb
źródło
2
+1, ponieważ jest to proste rozwiązanie, które działa w niektórych scenariuszach (dla luźnej definicji „działa”, mógłbym dodać).
kruk
2
Prawie to samo, co rozwiązanie namar0x0309, które jest znacznie bardziej eleganckie IMHO. Ale to tylko ja.
onitake
Ulepszyłem twój kod, aby faktycznie działał z minimalnymi modyfikacjami ;-)
rubenvb
9
-1 Jeśli masz sznur, prawdopodobnie masz do czynienia z postaciami wielobajtowymi. Gdybyś wiedział, że łańcuch można w sposób trywialny zamieniać, w pierwszej kolejności nie radziłbyś sobie z ciągiem. Bardziej prawdopodobne jest, że masz do czynienia z inną biblioteką, która oczekuje, że odpowiednio poradzisz sobie z przeciąganiem. Obcinanie wchars jest później błaganiem o trudny do wyśledzenia błąd. Ponadto powinieneś użyć „string string (w.begin (), w.end ());” jeśli miałbyś to zrobić, aby uniknąć pętli, która mogłaby wywołać wiele realokacji.
Kian
7

Wydaje mi się, że oficjalnym sposobem są wciąż szczegółowe codecvtaspekty (potrzebujesz jakiegoś tłumaczenia zależnego od lokalizacji), jak w

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

lub coś w tym rodzaju, nie mam wokół siebie działającego kodu. Ale nie jestem pewien, ile osób korzysta obecnie z tej maszyny i ilu po prostu prosi o wskaźniki do pamięci i pozwala ICU lub innej bibliotece obsłużyć krwawe szczegóły.

Christopher Creutzig
źródło
7

Istnieją dwa problemy z kodem:

  1. Konwersja w const std::string s( ws.begin(), ws.end() );nie jest wymagana do poprawnego odwzorowania szerokich znaków na ich wąski odpowiednik. Najprawdopodobniej każda szeroka postać będzie po prostu rzutem na typ char.
    Rozwiązanie tego problemu jest już podane w odpowiedzi przez kem i obejmuje narrowfunkcję ctypeaspektu ustawień regionalnych .

  2. Piszesz wyjście zarówno std::couti std::wcoutw tym samym programie. Zarówno couti wcoutsą związane z tym samym strumieniem ( stdout) i wyniki z użyciem takiego samego strumienia, zarówno w postaci strumienia bajtowo (co coutma miejsce) i szerokości zorientowanej strumień (jak wcoutnie) nie jest zdefiniowana.
    Najlepszą opcją jest unikanie miksowania wąskiego i szerokiego wyjścia do tego samego (podstawowego) strumienia. W przypadku stdout/ cout/ wcoutmożesz spróbować zmienić orientację stdoutpodczas przełączania między szerokim a wąskim wyjściem (lub odwrotnie):

    #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;
    }
Bart van Ingen Schenau
źródło
Tak, to rozwiązuje problem z używaniem cout i wcout.
BЈовић
7

Domyślne kodowanie:

  • Windows UTF-16.
  • Linux UTF-8.
  • MacOS UTF-8.

Ten kod ma dwie formy do konwersji std :: string na std :: wstring i std :: wstring na std :: string. Jeśli zanegujesz # jeśli zdefiniowano WIN32, otrzymasz ten sam wynik.

1. std :: string na std :: wstring

MultiByteToWideChar WinAPI

_mbstowcs_s_l

#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 do std :: string

WideCharToMultiByte WinAPI

_wcstombs_s_l

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. W systemie Windows musisz wydrukować Unicode, używając WinAPI.

WriteConsole

#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. W programie głównym.

#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. Wreszcie potrzebujesz potężnej i pełnej obsługi znaków Unicode w konsoli. Polecam ConEmu i ustawiam jako domyślny terminal w systemie Windows . Musisz podłączyć Visual Studio do ConEmu. Pamiętaj, że plik exe programu Visual Studio to devenv.exe

Testowane na Visual Studio 2017 z VC ++; std = c ++ 17.

Wynik

Wynik 1

Joma
źródło
6

Równie dobrze możesz po prostu użyć wąskiej metody aspektu ctype bezpośrednio:

#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 ();
    bufor std :: vector <char> (len + 1);
    std :: use_facet <std :: ctype <wchar_t>> (loc) .narrow (z, od + len, „_” i & bufor [0]);
    return std :: string (& buffer [0], & buffer [len]);
}
zalegalizować
źródło
6

W momencie pisania tej odpowiedzi wyszukiwarka Google numer jeden „konwersja ciągu znaków” wylądowałaby na tej stronie. Moja odpowiedź pokazuje, jak przekonwertować ciąg znaków na wstring, chociaż to nie jest właściwe pytanie i prawdopodobnie powinienem usunąć tę odpowiedź, ale jest to uważane za złą formę. Możesz przejść do odpowiedzi StackOverflow , która jest teraz wyżej w rankingu niż ta strona.


Oto sposób na połączenie ciągów strun, strun i mieszanych stałych strun z strunami. Użyj klasy 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();
Mark Lakata
źródło
13
To nie jest zamiana łańcuchów na ciągi znaków
poitroae,
1
@Michael Czy możesz wyjaśnić? Co z tym jest nieprawidłowe? Twój komentarz nie jest pomocny bez dalszych szczegółów.
Nate
1
jest to konwersja łańcucha do ciągu. tzn. przeciwieństwo pytania.
Jeff McClintock
4

Oprócz zwykłej konwersji typów, powinieneś także być świadomy faktycznego formatu łańcucha.

Podczas kompilacji dla zestawu znaków wielobajtowych Visual Studio i Win API zakłada UTF8 (w rzeczywistości kodowanie Windows, czyli Windows-28591 ).
Podczas kompilacji dla zestawu znaków Unicode Visual Studio i Win API zakłada UTF16.

Musisz więc przekonwertować ciąg z formatu UTF16 na format UTF8, a nie tylko konwertować na std :: string.
Stanie się to konieczne podczas pracy z formatami wieloznakowymi, takimi jak niektóre języki inne niż łacińskie.

Chodzi o to, aby zdecydować, że std::wstring zawsze reprezentuje UTF16 .
I std::string zawsze reprezentuje UTF8 .

Kompilator tego nie wymusza, jest to raczej dobra polityka. Zwróć uwagę na przedrostki ciągu, których używam do zdefiniowania UTF16 ( L ) i UTF8 ( u8 ).

Aby przekonwertować dwa typy, powinieneś użyć: 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;
}
Yochai Timmer
źródło
3

W moim przypadku muszę użyć znaku wielobajtowego (MBCS) i chcę użyć std :: string i std :: wstring. I nie można używać c ++ 11. Więc używam mbstowcs i wcstombs.

Wykonuję tę samą funkcję za pomocą new, delete [], ale jest to wolniejsze niż to.

Może to pomóc w jaki sposób: Konwersja między różnymi typami ciągów

EDYTOWAĆ

Jednak w przypadku konwersji na łańcuch i łańcuch źródłowy to nie alfabet i łańcuch wielobajtowy, to nie działa. Więc zmieniam wcstombs na 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);
}

EDYCJA, aby użyć „MultiByteToWideChar” zamiast „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);
}
heon
źródło
Jak używać „wcstombs_s” z gcc 4.8? Ponieważ widzę, że jest to funkcja C ++ 11.
cristian
@ Cristian Możesz użyć „niebezpiecznej” wersji tej funkcji wcstombs().
Vizor
3

To rozwiązanie jest zainspirowane rozwiązaniem dk123 , ale korzysta z zależnego od regionu aspektu codecvt. Wynik jest w postaci łańcucha zakodowanego w ustawieniach regionalnych zamiast w UTF-8 (jeśli nie jest ustawiony jako ustawienia regionalne):

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);
}

Szukałem tego, ale nie mogę go znaleźć. W końcu odkryłem, że mogę uzyskać właściwy aspekt, std::localeużywając std::use_facet()funkcji o właściwej nazwie typu. Mam nadzieję że to pomoże.

Daszek u czapki
źródło
Vizor, jakie są zalety (jeśli w ogóle) konwersji z aspektem zależnym od ustawień regionalnych?
Marc.2377,
Jeśli pracujesz z ciągami z systemu, na przykład z danych wejściowych konsoli.
Vizor,
1

W przypadku, gdy ktoś jest zainteresowany: Potrzebowałem klasy, które mogą być używane zamiennie, gdziekolwiek albo stringczy wstringbył oczekiwany. Następujące klasy convertible_string, w oparciu o rozwiązanie dk123 męska może być zainicjowany albo z string, char const*, wstringlub wchar_t const*mogą być przypisane do lub pośrednio przez konwertowana na stringlub wstring(a więc mogą być przekazywane do funkcji, które mają zarówno).

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_;
};
James Hirschorn
źródło
1
Wolę przechowywać std::wstringw klasie, niż przechowywać std::stringi wykonać konwersję do, std::wstringgdy jest to potrzebne, aby uzyskać std::wstring. Ponieważ std::wstringjest nieco szybszy std::stringi lepiej kompatybilny. Nawet zużywa więcej pamięci niż std::string.
0xAA55
0
#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); }
głęboki 125
źródło
-1

Używam poniżej, aby przekonwertować ciąg na ciąg.

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;
Bieg
źródło
Wygląda na to, że brakuje ci standardowego nagłówka ( <string>) i definicji WideCharToMultiByte()- czy to jakieś opakowanie std::wctomb()?
Toby Speight,
-3
// 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"
szyje
źródło
3
proszę wyjaśnij, co robisz w swojej odpowiedzi, w przeciwnym razie może zostać usunięty
CodeFanatic
1
Skąd pochodzi funkcja UTF8string?
Jean-Christophe Blanchard