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?
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 construireCStringT
des objets à partir destd::string
des objets avec des caractères encastrésNUL
.
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.
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.
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);
}
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);
Cela fonctionne très bien:
//Convert CString to std::string
inline std::string to_string(const CString& cst)
{
return CT2A(cst.GetString());
}
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;
}
(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
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();
}
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.
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
(utilisantchar
) etCStringW
(utilisantwchar_t
). - alors que
wchar_t
sur Windows est ubiquitously utilisé pour stocker des unités de code encodées UTF-16, en utilisantchar
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 destd::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() };
}
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);