Hoe converteer je CString en std::string std::wstring naar elkaar?

CStringis best handig, terwijl std::stringbeter compatibel is met STL-container. Ik gebruik hash_map. hash_mapondersteunt echter geen CStrings als sleutels, dus ik wil de CStringconverteren naar een std::string.

Het schrijven van een CStringhash-functie lijkt veel tijd te kosten.

CString -----> std::string

Hoe kan ik dit doen?

std::string -----> CString:
inline CString toCString(std::string const& str)
{
    return CString(str.c_str()); 
}

Heb ik gelijk?


BEWERKEN:

Hier zijn meer vragen:

Hoe kan ik wstringconverteren naar CStringen vice versa?

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

Is er een probleem hiermee?

Hoe kan ik bovendien converteren van std::wstringnaar std::stringen vice versa?


Antwoord 1, autoriteit 100%

Volgens CodeGuru:

CStringnaar std::string:

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

MAAR:std::stringkan niet altijd construeren vanuit een LPCTSTR. d.w.z. de code zal mislukken voor UNICODE-builds.

Aangezien std::stringalleen kan construeren uit LPSTR/ LPCSTR, kan een programmeur die VC++ 7.x of beter gebruikt conversie gebruiken klassen zoals CT2CAals tussenpersoon.

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::stringnaar CString: (Van Veelgestelde vragen over CString van Visual Studio…)

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

CStringTkan construeren uit zowel tekenreeksen als tekenreeksen met brede tekens. dwz het kan converteren van char*(dwz LPSTR) of van wchar_t*(LPWSTR).

Met andere woorden, char-specialisatie (van CStringT) dwz CStringA, wchar_t-specilisatie CStringW, en TCHAR-specialisatie CStringkan worden opgebouwd uit charof brede tekens, null beëindigd (null-beëindiging is hier erg belangrijk )tekenreeksbronnen.
Hoewel IInspectablehet gedeelte “null-termination” wijzigt in de opmerkingen:

NUL-beëindiging is niet vereist.
CStringTheeft conversieconstructors die een expliciet lengteargument hebben. Dit betekent ook dat u CStringT-objecten kunt maken van std::string-objecten met ingesloten NUL-tekens.


Antwoord 2, autoriteit 36%

Los dat op door std::basic_string<TCHAR>te gebruiken in plaats van std::stringen het zou goed moeten werken, ongeacht je tekeninstelling.


Antwoord 3, autoriteit 6%

Het is efficiënter om CStringte converteren naar std::stringmet behulp van de conversie waarbij de lengte is opgegeven.

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

In een strakke lus zorgt dit voor een aanzienlijke prestatieverbetering.


Antwoord 4, autoriteit 5%

Als je iets meer C++-achtigs wilt, dan is dit wat ik gebruik. Hoewel het afhankelijk is van Boost, is dat slechts voor uitzonderingen. U kunt degenen die het verlaten eenvoudig verwijderen om alleen afhankelijk te zijn van de STL en de WideCharToMultiByte()Win32 API-aanroep.

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

Antwoord 5, autoriteit 4%

Is er eenprobleem?

Er zijn verschillende problemen:

  • CStringis een sjabloonspecialisatie van CStringT. Afhankelijk van het BaseTypedat het tekentype beschrijft, zijn er twee concrete specialisaties: CStringA(met behulp van char) en CStringW(met behulp van wchar_t).
  • Hoewel wchar_top Windows alom wordt gebruikt om UTF-16-gecodeerde code-eenheden op te slaan, is het gebruik van chardubbelzinnig. De laatste slaat gewoonlijk ANSI-gecodeerde tekens op, maar kan ook ASCII-, UTF-8- of zelfs binaire gegevens opslaan.
  • We kennen de tekencodering (of zelfs het tekentype) van CStringniet (die wordt bestuurd door het preprocessor-symbool _UNICODE), waardoor de vraag dubbelzinnig is. We kennen ook de gewenste tekencodering van std::stringniet.
  • Conversie tussen Unicode en ANSI is inherent verliesgevend: ANSI-codering kan alleen een subset van de Unicode-tekenset vertegenwoordigen.

Om deze problemen aan te pakken, ga ik ervan uit dat wchar_tUTF-16-gecodeerde code-eenheden zal opslaan en charUTF-8-octetreeksen zal bevatten. Dat is de enige redelijke keuze die u kunt maken om ervoor te zorgen dat bron- en bestemmingsreeksen dezelfde informatie behouden, zonder de oplossing te beperken tot een subset van de bron- of doeldomeinen.

De volgende implementaties converteren tussen CStringA/CStringWen std::wstring/std::stringmapping van UTF-8 naar UTF-16 en vice versa:

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

De overige twee functies construeren C++-tekenreeksobjecten van MFC-tekenreeksen, waarbij de codering ongewijzigd blijft. Merk op dat hoewel de vorige functies niet overweg kunnen met ingesloten NUL-tekens, deze functies daar immuun voor zijn.

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

Antwoord 6, autoriteit 3%

(Sinds VS2012 …en in ieder geval tot VS2017 v15.8.1)

Omdat het een MFC-project is & CString is een MFC-klasse, MS biedt een technische opmerking TN059: MFC MBCS/Unicode gebruiken Conversiemacro’sen algemene conversiemacro’s:

A2CW      (LPCSTR)  -> (LPCWSTR)  
A2W       (LPCSTR)  -> (LPWSTR)  
W2CA      (LPCWSTR) -> (LPCSTR)  
W2A       (LPCWSTR) -> (LPSTR)  

Gebruik:

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" **
}

Voetnoten:

(1) Om ervoor te zorgen dat de conversie-macro’s ruimte hebben om de tijdelijke lengte op te slaan, is het noodzakelijk om een lokale variabele genaamd _convertte declareren die dit doet in elke functie die de conversie gebruikt macro’s. Dit wordt gedaan door de macro USES_CONVERSIONaan te roepen. In VS2017 MFC-code (atlconv.h) ziet het er als volgt uit:

#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

Antwoord 7, autoriteit 2%

Dit werkt prima:

//Convert CString to std::string
inline std::string to_string(const CString& cst)
{
    return CT2A(cst.GetString());
}

Antwoord 8

Dit is een vervolg op het antwoord van Sal, waar hij/zij de oplossing heeft gegeven:

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

Dit is ook handig bij het converteren van een niet-typische C-String naar een std::string

Een use case voor mij was het hebben van een vooraf toegewezen char-array (zoals C-String), maar het is niet NUL-beëindigd. (d.w.z. SHA-digest).
Met de bovenstaande syntaxis kan ik de lengte van de SHA-digest van de char-array specificeren, zodat std::string niet hoeft te zoeken naar de afsluitende NUL-char, die er al dan niet is.

Zoals:

unsigned char hashResult[SHA_DIGEST_LENGTH];    
auto value = std::string(reinterpret_cast<char*>hashResult, SHA_DIGEST_LENGTH);

Antwoord 9

van dit bericht (Bedankt Mark Ransom)

CString converteren naar string (VC6)

Ik heb dit getest en het werkt prima.

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

Antwoord 10

U kunt CT2CA

. gebruiken

CString datasetPath;
CT2CA st(datasetPath);
string dataset(st);

Antwoord 11

om CString to std::string. U kunt dit formaat gebruiken.

std::string sText(CW2A(CSText.GetString(), CP_UTF8 ));

Antwoord 12

Werkt voor mij:

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

Antwoord 13

Alle andere antwoorden kwamen niet helemaal overeen met wat ik zocht, namelijk om CStringon-the-fly te converteren in plaats van het resultaat in een variabele op te slaan.

De oplossing is vergelijkbaar met hierboven, maar we hebben nog een stap nodig om een naamloos object te instantiëren. Ik illustreer met een voorbeeld. Hier is mijn functie die std::stringnodig heeft, maar ik heb 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;
}

Hoe noem je het als je een CStringhebt?

std::string firstName = "First";
CString lastName = _T("Last");
writeLog( firstName + ", " + std::string( CT2A( lastName ) ) );     

Merk op dat de laatste regel geen directe typecast is, maar we maken een naamloos std::stringobject en leveren de CStringvia zijn constructor.


Antwoord 14

Als u eenvoudig wilt converteren tussen andere typen tekenreeksen, is het misschien de _bstr_tklasse zou meer geschikt zijn? Het ondersteunt conversie tussen char, wchar_ten BSTR.


Antwoord 15

Een interessante benadering is om CStringnaar CStringAte casten in een string-constructor. In tegenstelling tot std::string s((LPCTSTR)cs);werkt dit zelfs als _UNICODEis gedefinieerd. Als dat echter het geval is, zal dit de conversie van Unicode naar ANSI uitvoeren, dus het is onveilig voor hogere Unicode-waarden buiten de ASCII-tekenset. Een dergelijke conversie is onderhevig aan de preprocessordefinitie _CSTRING_DISABLE_NARROW_WIDE_CONVERSION. https://msdn.microsoft.com/en-us/library/5bzxfsea. aspx

       CString s1("SomeString");
        string s2((CStringA)s1);

Antwoord 16

Je kunt CStringvrij casten naar const char*en het dan toewijzen aan een std::stringals volgt:

CString cstring("MyCString");
std::string str = (const char*)cstring;

Other episodes