Jak przekonwertować CString i: std:: string: std:: wstring na siebie?

CString jest bardzo poręczny, natomiast {[4] } jest bardziej kompatybilny z kontenerem STL. Używam hash_map. Jednak hash_map nie obsługuje CString jako klucza, więc chcę przekonwertować CString na std::string.

Napisanie CString funkcji hash zajmuje dużo czasu.

CString -----> std::string
Jak mogę to zrobić?
std::string -----> CString:

inline CString toCString(std::string const& str)
{
    return CString(str.c_str()); 
}
Mam rację?

EDIT:

Oto kolejne pytania:

Jak mogę przekonwertować wstring, CString do siebie?

//wstring -> CString,
std::wstring src;
CString result(src.c_str());
//CString->wstring. 
CString src;
::std::wstring des(src.GetString());

Jest Jakiś problem?

Jak mogę przekonwertować std::wstring, std::string do siebie?

Author: Peter Mortensen, 2008-11-03

13 answers

Według CodeGuru :

CString do std::string:

CString cs("Hello");
std::string s((LPCTSTR)cs);

Ale: std::string nie zawsze można konstruować z LPCTSTR. tzn. kod nie powiedzie się dla kompilacji UNICODE.

Jako {[4] } można konstruować tylko z LPSTR / LPCSTR, programista korzystający z VC++ 7.x lub lepiej może używać klas konwersji, takich jak CT2CA jako pośrednika.

CString cs ("Hello");
// Convert a TCHAR string to a LPCSTR
CT2CA pszConvertedAnsiString (cs);
// construct a std::string using the LPCSTR input
std::string strStd (pszConvertedAnsiString);

std::string na CString: (od Visual Studio ' S Cstrring FAQs...)

std::string s("Hello");
CString cs(s.c_str());

CStringT can konstruuj z łańcuchów znaków lub szerokich znaków. tzn. może konwertować z char* (tzn. LPSTR) lub z wchar_t* (LPWSTR).

Innymi słowy, char-specjalizacja (z CStringT), czyli CStringA, wchar_t-specilization CStringW i TCHAR-specialization CString mogą być skonstruowane z char lub szerokiego znaku, zakończonego znakiem null (zakończenie null jest tutaj bardzo ważne) źródeł łańcuchów.
Althoug IInspectable zmienia część " null-termination "W komentarze :

Nul-wypowiedzenie nie jest wymagane .
CStringT ma konstruktory konwersji, które przyjmują jawny argument długości. Oznacza to również, że można konstruować obiekty CStringT z obiektów std::string z osadzonymi znakami NUL.

 81
Author: VonC,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:25

Rozwiąż to używając std::basic_string<TCHAR> zamiast std::string i powinno działać dobrze niezależnie od ustawienia postaci.

 33
Author: OJ.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-03 09:36:36

Bardziej efektywna jest konwersja CString na std::string przy użyciu konwersji, w której określona jest długość.

CString someStr("Hello how are you");
std::string std(somStr, someStr.GetLength());

W ciasnej pętli powoduje to znaczną poprawę wydajności.

 5
Author: Sal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-09 18:19:15

Jeśli chcesz coś bardziej C++ - like, to jest to, co używam. Chociaż zależy to od wzmocnienia, to tylko dla WYJĄTKÓW. Możesz łatwo usunąć te, które pozostawiają go w zależności tylko od STL i wywołania API WideCharToMultiByte() Win32.

#include <string>
#include <vector>
#include <cassert>
#include <exception>

#include <boost/system/system_error.hpp>
#include <boost/integer_traits.hpp>

/**
 * Convert a Windows wide string to a UTF-8 (multi-byte) string.
 */
std::string WideStringToUtf8String(const std::wstring& wide)
{
    if (wide.size() > boost::integer_traits<int>::const_max)
        throw std::length_error(
            "Wide string cannot be more than INT_MAX characters long.");
    if (wide.size() == 0)
        return "";

    // Calculate necessary buffer size
    int len = ::WideCharToMultiByte(
        CP_UTF8, 0, wide.c_str(), static_cast<int>(wide.size()), 
        NULL, 0, NULL, NULL);

    // Perform actual conversion
    if (len > 0)
    {
        std::vector<char> buffer(len);
        len = ::WideCharToMultiByte(
            CP_UTF8, 0, wide.c_str(), static_cast<int>(wide.size()),
            &buffer[0], static_cast<int>(buffer.size()), NULL, NULL);
        if (len > 0)
        {
            assert(len == static_cast<int>(buffer.size()));
            return std::string(&buffer[0], buffer.size());
        }
    }

    throw boost::system::system_error(
        ::GetLastError(), boost::system::system_category);
}
 4
Author: thehouse,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-15 07:42:50

Jest to kontynuacja odpowiedzi Sal, w której podał rozwiązanie:]}

CString someStr("Hello how are you");
std::string std(somStr, someStr.GetLength());

Jest to przydatne również podczas konwersji nietypowego ciągu C na std:: string

Przypadek użycia dla mnie miał wstępnie przydzieloną tablicę znaków( jak łańcuch C), ale nie jest zakończony znakiem NUL. (tj. SHA digest). Powyższa składnia pozwala mi określić długość skrótu SHA tablicy znaków, aby std:: string nie musiał szukać kończącego znaku NUL, który może być lub nie tam.

Takie jak:

unsigned char hashResult[SHA_DIGEST_LENGTH];    
auto value = std::string(reinterpret_cast<char*>hashResult, SHA_DIGEST_LENGTH);
 1
Author: Neil,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-10 19:04:21

To działa dobrze:

//Convert CString to std::string
inline std::string to_string(const CString& cst)
{
    return CT2A(cst.GetString());
}
 1
Author: freeze,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-05 21:28:36

From this post (Thank you Mark Ransom )

Convert CString to string (VC6)

Przetestowałem to i działa dobrze.

std::string Utils::CString2String(const CString& cString) 
{
    std::string strStd;

    for (int i = 0;  i < cString.GetLength();  ++i)
    {
        if (cString[i] <= 0x7f)
            strStd.append(1, static_cast<char>(cString[i]));
        else
            strStd.append(1, '?');
    }

    return strStd;
}
 1
Author: Pat. ANDRIA,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-21 08:55:32

(od VS2012 ...i przynajmniej do VS2017 v15. 8. 1)

Ponieważ jest to projekt MFC, a CString jest klasą MFC, MS dostarcza notatkę techniczną TN059: używanie makr konwersji MFC MBCS/Unicode i ogólnych makr konwersji:
A2CW      (LPCSTR)  -> (LPCWSTR)  
A2W       (LPCSTR)  -> (LPWSTR)  
W2CA      (LPCWSTR) -> (LPCSTR)  
W2A       (LPCWSTR) -> (LPSTR)  

Użycie:

void Example() // ** UNICODE case **
{
    USES_CONVERSION; // (1)

    // CString to std::string / std::wstring
    CString strMfc{ "Test" }; // strMfc = L"Test"
    std::string strStd = W2A(strMfc); // ** Conversion Macro: strStd = "Test" **
    std::wstring wstrStd = strMfc.GetString(); // wsrStd = L"Test"

    // std::string to CString / std::wstring
    strStd = "Test 2";
    strMfc = strStd.c_str(); // strMfc = L"Test 2"
    wstrStd = A2W(strStd.c_str()); // ** Conversion Macro: wstrStd = L"Test 2" **

    // std::wstring to CString / std::string 
    wstrStd = L"Test 3";
    strMfc = wstrStd.c_str(); // strMfc = L"Test 3"
    strStd = W2A(wstrStd.c_str()); // ** Conversion Macro: strStd = "Test 3" **
}

--

Przypisy:

(1) aby makra conversion-miały przestrzeń do przechowywania tymczasowej długości, konieczne jest zadeklarowanie zmiennej lokalnej o nazwie _convert, która robi to w każdej funkcji, która wykorzystuje makra konwersji. Odbywa się to poprzez wywołanie makra USES_CONVERSION. W kodzie VS2017 MFC (atlconv.h) wygląda tak:

#ifndef _DEBUG
    #define USES_CONVERSION int _convert; (_convert); UINT _acp = ATL::_AtlGetConversionACP() /*CP_THREAD_ACP*/; (_acp); LPCWSTR _lpw; (_lpw); LPCSTR _lpa; (_lpa)
#else
    #define USES_CONVERSION int _convert = 0; (_convert); UINT _acp = ATL::_AtlGetConversionACP() /*CP_THREAD_ACP*/; (_acp); LPCWSTR _lpw = NULL; (_lpw); LPCSTR _lpa = NULL; (_lpa)
#endif
 1
Author: Amit G.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-21 11:28:38

Działa dla mnie:

std::wstring CStringToWString(const CString& s)
{
    std::string s2;
    s2 = std::string((LPCTSTR)s);
    return std::wstring(s2.begin(),s2.end());
}

CString WStringToCString(std::wstring s)
{
    std::string s2;
    s2 = std::string(s.begin(),s.end());
    return s2.c_str();
}
 0
Author: user5546107,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-10 10:10:29

Wszystkie inne odpowiedzi nie do końca odnosiły się do tego, czego szukałem, czyli do konwersji CString w locie, a nie do przechowywania wyniku w zmiennej.

Rozwiązanie jest podobne do powyższego, ale potrzebujemy jeszcze jednego kroku, aby utworzyć instancję bezimiennego obiektu. Ilustruję przykładem. Oto moja funkcja, która potrzebuje std::string, ale mam CString.

void CStringsPlayDlg::writeLog(const std::string &text)
{
    std::string filename = "c:\\test\\test.txt";

    std::ofstream log_file(filename.c_str(), std::ios_base::out | std::ios_base::app);

    log_file << text << std::endl;
}

Jak to nazwać, gdy masz CString?

std::string firstName = "First";
CString lastName = _T("Last");

writeLog( firstName + ", " + std::string( CT2A( lastName ) ) );     

Zauważ, że ostatnia linia nie jest typem bezpośrednim, ale tworzymy obiekt bezimienny std::string i dostarcza CString poprzez jego konstruktor.

 0
Author: zar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-29 21:15:37
Czy jest jakiś problem?

Istnieje kilka kwestii:

  • CString jest specjalizacją szablonu CStringT. W zależności od typu podstawowego opisującego typ znaku, istnieją dwie konkretne specjalizacje: CStringA (za pomocą char) i CStringW (za pomocą wchar_t).
  • podczas gdy wchar_t w systemie Windows jest powszechnie używany do przechowywania jednostek kodowanych UTF-16, użycie char jest niejednoznaczne. Ten ostatni zwykle przechowuje kodowane ANSI znaków, ale może również przechowywać dane ASCII, UTF-8, a nawet binarne.
  • nie znamy kodowania znaków (ani nawet typu znaków) CString (które jest kontrolowane przez symbol preprocesora _UNICODE), co sprawia, że pytanie jest niejednoznaczne. Nie znamy również pożądanego kodowania znaków std::string.
  • konwersja pomiędzy Unicode i ANSI jest z natury stratna: kodowanie ANSI może reprezentować tylko podzbiór zestawu znaków Unicode.

Aby rozwiązać te problemy, idę założenie, że wchar_t będzie przechowywać jednostki kodowane UTF-16, A char będzie przechowywać sekwencje oktetów UTF-8. Jest to jedyny rozsądny wybór, jaki można podjąć, aby zapewnić, że ciągi źródłowe i docelowe zachowują te same informacje, bez ograniczania rozwiązania do podzbioru domen źródłowych lub docelowych.

Następujące implementacje konwertują między CStringA/CStringW oraz std::wstring/std::string W przypadku UTF-8 do UTF-16 i odwrotnie:

#include <string>
#include <atlconv.h>

std::string to_utf8(CStringW const& src_utf16)
{
    return { CW2A(src_utf16.GetString(), CP_UTF8).m_psz };
}

std::wstring to_utf16(CStringA const& src_utf8)
{
    return { CA2W(src_utf8.GetString(), CP_UTF8).m_psz };
}

Pozostałe dwie funkcje konstruują C++ string objects from MFC strings, pozostawiając kodowanie bez zmian. Zauważ, że podczas gdy poprzednie funkcje nie radzą sobie z osadzonymi znakami NUL, funkcje te są na to Odporne.

#include <string>
#include <atlconv.h>

std::string to_std_string(CStringA const& src)
{
    return { src.GetString(), src.GetString() + src.GetLength() };
}

std::wstring to_std_wstring(CStringW const& src)
{
    return { src.GetString(), src.GetString() + src.GetLength() };
}
 0
Author: IInspectable,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-06 10:07:43

Jeśli chcesz łatwo konwertować między innymi typami łańcuchów, być może _bstr_t zajęcia byłyby bardziej odpowiednie? Obsługuje konwersację pomiędzy char, wchar_t i BSTR.

 -1
Author: OJ.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-15 07:43:15

Ciekawym podejściem jest rzut CString do CStringA wewnątrz konstruktora string. W przeciwieństwie do std::string s((LPCTSTR)cs); to zadziała nawet jeśli _UNICODE jest zdefiniowane. Jeśli jednak tak się stanie, spowoduje to konwersję z Unicode do ANSI, więc jest to niebezpieczne dla wyższych wartości Unicode poza zestawem znaków ASCII. Taka konwersja podlega definicji preprocesora _CSTRING_DISABLE_NARROW_WIDE_CONVERSION. https://msdn.microsoft.com/en-us/library/5bzxfsea.aspx

        CString s1("SomeString");
        string s2((CStringA)s1);
 -1
Author: u8it,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-04 20:20:06