Comment convertir CString et: std:: string:std:: wstring?

CString est très pratique, tandis que std::string est plus compatible avec le conteneur STL. J'utilise hash_map . Cependant, hash_map ne supporte pas CString comme clé, donc je veux convertir CString en std::string .

écrire une fonction de hachage CString semble prendre beaucoup de temps.

CString -----> std::string

Comment faire?

std::string -----> CString:

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

n'est-ce pas?


EDIT:

voici plus de questions:

Comment puis-je convertir wstring , CString l'un à l'autre?

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

y a-t-il un problème?

Comment puis-je convertir std::wstring , std::string l'un à l'autre?

66
demandé sur Peter Mortensen 2008-11-03 09:58:46

13 réponses

selon CodeGuru :

CString à std::string :

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

mais: std::string ne peut pas toujours construire à partir d'un LPCTSTR . c'est-à-dire que le code échouera pour les constructions UNICODE.

Comme std::string ne peut construire que de LPSTR / LPCSTR , un programmeur qui utilise VC++ 7.x ou mieux peut utiliser des classes de conversion telles que CT2CA comme intermédiaire.

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 à CString : (de CString FAQ de Visual Studio... )

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

CStringT peut être construit à partir de chaînes de caractères ou larges. c'est-à-dire qu'elle peut être convertie de char* (c'est-à-dire LPSTR ) ou de wchar_t* ( LPWSTR ).

En d'autres termes, char-spécialisation (de CStringT ) c'est à dire CStringA , wchar_t -specilization CStringW , et TCHAR spécialisation CString peuvent être construits à partir soit char ou à caractère large, null (null-résiliation est très important ici) chaîne de sources.

Althoug IInspectable modifie la partie "null-termination dans les commentaires :

NUL de terminaison n'est pas nécessaire .

CStringT a des constructeurs de conversion qui prennent un argument de longueur explicite. Cela signifie également que vous pouvez construire CStringT des objets à partir de std::string des objets avec des caractères encastrés NUL .

81
répondu VonC 2017-05-23 12:18:25

résolvez cela en utilisant std::basic_string<TCHAR> au lieu de std::string et il devrait fonctionner très bien indépendamment de votre jeu de caractères.

33
répondu OJ. 2008-11-03 09:36:36

il est plus efficace de convertir CString en std::string en utilisant la conversion où la longueur est spécifiée.

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

en boucle serrée cela améliore considérablement les performances.

5
répondu Sal 2011-08-09 18:19:15

Si vous voulez quelque chose de plus C++, c'est ce que j'utilise. Bien que cela dépende de Boost, c'est juste pour les exceptions. Vous pouvez facilement supprimer ceux qui le laissent dépendre uniquement de L'appel STL et de L'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
répondu thehouse 2011-05-15 07:42:50

il s'agit d'une suite à la réponse de Sal, où il/elle a fourni la solution:

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

ceci est également utile lors de la conversion d'une chaîne C non typique en une chaîne std:: string

un cas d'utilisation pour moi était d'avoir un tableau de char pré-alloué (comme C-String), mais il n'est pas nul terminé. (c.-à-d. SHA digest). La syntaxe ci-dessus me permet de spécifier la longueur du Sha digest du tableau char pour que std:: string n'ait pas à chercher la terminaison NUL char, qui peut être ou ne pas être là.

tels que:

unsigned char hashResult[SHA_DIGEST_LENGTH];    
auto value = std::string(reinterpret_cast<char*>hashResult, SHA_DIGEST_LENGTH);
1
répondu Neil 2016-03-10 19:04:21

Cela fonctionne très bien:

//Convert CString to std::string
inline std::string to_string(const CString& cst)
{
    return CT2A(cst.GetString());
}
1
répondu freeze 2017-02-05 21:28:36

de ce post (Merci Mark Ransom )

convertir CString en chaîne (VC6)

j'ai testé et cela fonctionne très bien.

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
répondu Pat. ANDRIA 2018-08-21 08:55:32

(depuis VS2012 ...et au moins jusqu'à VS2017 v15.8.1)

Puisque c'est un projet MFC & CString est une classe MFC, MS fournit une Note Technique TN059: à l'Aide de MFC MBCS de Conversion Unicode/Macros et le Générique de Macros de Conversion:

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

Utiliser:

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

--

notes:

(1) pour la conversion-macros d'avoir de l'espace à stocker la longueur temporaire, il est nécessaire de déclarer une variable locale appelée _convert qui fait cela dans chaque fonction qui utilise les macros de conversion. Ceci est fait en invoquant la macro USES_CONVERSION . Dans le code MFC VS2017 (atlconv.h) il ressemble à ceci:

#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
répondu Amit G. 2018-08-21 11:28:38

Fonctionne pour moi:

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
répondu user5546107 2015-11-10 10:10:29

toutes les autres réponses n'ont pas tout à fait abordé ce que je cherchais qui était de convertir CString à la volée plutôt que de stocker le résultat dans une variable.

la solution est similaire à ci-dessus, mais nous avons besoin d'un pas de plus pour instancier un objet sans nom. Je suis là pour illustrer avec un exemple. Voici ma fonction qui nécessite std::string mais j'ai 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;
}

comment l'appeler quand vous avez un CString ?

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

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

notez que la dernière ligne n'est pas une typographie directe mais nous créons un objet std::string sans nom et fournissons le CString via son constructeur.

0
répondu zar 2017-06-29 21:15:37

Est-il tout problème?

il y a plusieurs questions:

  • CString est un modèle de spécialisation de CStringT . Selon le Type de base décrivant le type de caractère, il existe deux spécialisations concrètes: CStringA (utilisant char ) et CStringW (utilisant wchar_t ).
  • alors que wchar_t sur Windows est ubiquitously utilisé pour stocker des unités de code encodées UTF-16, en utilisant char est ambigu. Ce dernier stocke généralement des caractères encodés ANSI, mais peut aussi stocker des données ASCII, UTF-8, ou même binaires.
  • nous ne connaissons pas l'encodage des caractères (ou même le type de caractère) de CString (qui est contrôlé par le symbole de préprocesseur _UNICODE ), ce qui rend la question ambiguë. Nous ne savons pas souhaité encodage des caractères de std::string .
  • la conversion entre Unicode et ANSI est intrinsèquement une perte: l'encodage ANSI ne peut représenter qu'un sous-ensemble du jeu de caractères Unicode.

pour répondre à ces questions, je vais supposer que wchar_t va stocker des unités de code encodées UTF-16, et char va contenir des séquences D'octets UTF-8. C'est le seul choix raisonnable que vous pouvez faire pour vous assurer que les chaînes source et destination conservent les mêmes informations, sans limiter la solution à un sous-ensemble des domaines source ou destination.

les implémentations suivantes convertissent entre CStringA / CStringW et std::wstring / std::string cartographie de UTF-8 à UTF-16 et 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 };
}

les deux fonctions restantes construisent des objets C++ string à partir de chaînes MFC, laissant l'encodage inchangé. Notez que bien que les fonctions précédentes ne peuvent pas faire face à des caractères NULL intégrés, ces fonctions sont immunisées.

#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
répondu IInspectable 2018-09-06 10:07:43

si vous cherchez à convertir facilement entre d'autres types de cordes, peut-être la classe _bstr_t serait-elle plus appropriée? Il supporte la conversation entre char , wchar_t et BSTR .

-1
répondu OJ. 2011-05-15 07:43:15

une approche intéressante est de lancer CString à CStringA à l'intérieur d'un string constructeur. Contrairement à std::string s((LPCTSTR)cs); , cela fonctionnera même si _UNICODE est défini. Cependant, si c'est le cas, cela effectuera la conversion D'Unicode en ANSI, donc il est dangereux pour les valeurs supérieures D'Unicode au-delà du jeu de caractères ASCII. Cette conversion est soumise à la définition de préprocesseur _CSTRING_DISABLE_NARROW_WIDE_CONVERSION . https://msdn.microsoft.com/en-us/library/5bzxfsea.aspx

        CString s1("SomeString");
        string s2((CStringA)s1);
-1
répondu u8it 2018-09-04 20:20:06