Comment convertir CString et :: std :: string :: std :: wstring l'un vers l'autre?
Question
CString
est assez pratique, tandis que std::string
est plus compatible avec le conteneur STL.
J'utilise hash_map
. Cependant, wstring
ne prend pas en charge std::wstring
la clé, je souhaite donc convertir <=> en <=>.
L'écriture d'une <=> fonction de hachage semble prendre beaucoup de temps.
CString -----> std::string
Comment puis-je faire cela?
std::string -----> CString:
inline CString toCString(std::string const& str)
{
return CString(str.c_str());
}
Ai-je raison?
EDIT:
Voici d'autres questions:
Comment puis-je convertir <=>, <=> les uns aux autres?
//wstring -> CString,
std::wstring src;
CString result(src.c_str());
//CString->wstring.
CString src;
::std::wstring des(src.GetString());
Existe-t-il un problème ?
Comment puis-je convertir <=>, <=> les uns aux autres?
La solution
Selon CodeGuru :
CString
à std::string
:
CString cs("Hello");
std::string s((LPCTSTR)cs);
MAIS: LPCTSTR
ne peut pas toujours construire à partir d'un LPSTR
. le code échouera pour les versions UNICODE.
Comme LPCSTR
ne peut construire qu'à partir de CT2CA
/ CStringT
, un programmeur utilisant VC ++ 7.x ou une version supérieure peut utiliser des classes de conversion telles que char*
en tant qu'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);
wchar_t*
à LPWSTR
: (De FAQ sur CString de Visual Studio. .. )
std::string s("Hello");
CString cs(s.c_str());
CStringA
peut construire à partir de chaînes de caractères ou de chaînes de caractères larges. c'est-à-dire qu'il peut convertir à partir de wchar_t
(c'est-à-dire CStringW
) ou de TCHAR
(char
).
En d'autres termes, la spécialisation (de NUL
), c'est-à-dire <=>, <=> - spécification <=>, et <=> - spécialisation <=> peut être construite à partir de <=> ou large- character, null terminé (les terminaisons null sont très importantes ici) sources de chaînes.
Althoug IInspectable modifie la & Quot; null-résiliation & Quot; partie dans les commentaires :
La terminaison NUL n'est pas requise .
<=> a des constructeurs de conversion qui prennent un argument de longueur explicite. Cela signifie également que vous pouvez construire <=> des objets à partir de <=> objets avec des <=> caractères incorporés.
Autres conseils
Résolvez-le en utilisant std::basic_string<TCHAR>
au lieu de std::string
et tout devrait bien se passer, quel que soit le type de caractère que vous choisissez.
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, ce n'est que des exceptions. Vous pouvez facilement supprimer ceux qui le quittent pour qu'ils ne dépendent que de la STL et de WideCharToMultiByte()
l'appel d'API 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);
}
(Depuis VS2012 ... et au moins jusqu'à VS2017 v15.8.1)
Puisqu'il s'agit d'un projet MFC & amp; CString est une classe MFC, MS fournit une note technique TN059: Utilisation de MFC MBCS / Unicode Macros de conversion et macros de conversion génériques:
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 de bas de page:
(1) Pour que les macros de conversion disposent d'un espace pour stocker la longueur temporaire, il est nécessaire de déclarer une variable locale appelée _convert
qui le fait dans chaque fonction utilisant les macros de conversion. Ceci est fait en appelant 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
Ceci fait suite à la réponse de Sal dans laquelle il a fourni la solution:
CString someStr("Hello how are you");
std::string std(somStr, someStr.GetLength());
Ceci est utile également lors de la conversion d'une C-String non typique en std :: string
Un cas d'utilisation pour moi était d'avoir un tableau de caractères pré-alloué (comme C-String), mais il n'est pas terminé par NUL. (c'est-à-dire SHA Digest). La syntaxe ci-dessus me permet de spécifier la longueur du résumé SHA du tableau de caractères de sorte que std :: string ne doive pas rechercher le caractère de fin NUL, 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 bien:
//Convert CString to std::string
inline std::string to_string(const CString& cst)
{
return CT2A(cst.GetString());
}
de ce message ( Mark Ransom )
Convertir CString en chaîne (VC6)
J'ai testé cela et cela fonctionne 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;
}
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'abordaient pas tout à fait ce que je cherchais, à savoir convertir CString
à la volée au lieu de stocker le résultat dans une variable.
La solution est similaire à celle ci-dessus, mais nous avons besoin d’une étape supplémentaire pour instancier un objet sans nom. Je suis illustrant avec un exemple. Voici ma fonction qui nécessite std::string
mais j'ai <=>.
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 <=>?
std::string firstName = "First";
CString lastName = _T("Last");
writeLog( firstName + ", " + std::string( CT2A( lastName ) ) );
Notez que la dernière ligne n'est pas un transtypage direct, mais nous créons un objet sans nom <=> et fournissons le <=> via son constructeur.
Existe-t-il un problème ?
Il existe plusieurs problèmes:
-
CString
est une spécialisation de modèle de CStringT . Selon le BaseType décrivant le type de caractère, il existe deux spécialisations concrètes:CStringA
(utilisantchar
) etCStringW
(utilisantwchar_t
). - Alors que
_UNICODE
sur Windows est utilisé de manière omniprésente pour stocker des unités de code codées UTF-16, l'utilisation destd::string
est ambiguë. Ce dernier stocke généralement les caractères encodés en ANSI, mais peut également stocker des données ASCII, UTF-8 ou même binaires. - Nous ne connaissons pas l'encodage des caractères (ni même le type de caractère) de
std::wstring
(contrôlé par le symbole du préprocesseur <=>), ce qui rend la question ambiguë. Nous ne connaissons pas non plus le codage de caractères souhaité de <=>. - La conversion entre Unicode et ANSI entraîne des pertes inhérentes: le codage ANSI ne peut représenter qu'un sous-ensemble du jeu de caractères Unicode.
Pour résoudre ces problèmes, je suppose que <=> stockera les unités de code codées UTF-16 et <=> conservera les 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 cible conservent les mêmes informations, sans limiter la solution à un sous-ensemble des domaines source ou cible.
Les implémentations suivantes convertissent entre <=> / <=> et <=> / <=> le mappage de UTF-8 à UTF-16 et inversement:
#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 chaîne C ++ à partir de chaînes MFC, en laissant le codage inchangé. Notez que bien que les fonctions précédentes ne puissent pas gérer les caractères NUL intégrés, ces fonctions sont immunisées contre cela.
#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() };
}
Vous pouvez utiliser CT2CA
CString datasetPath;
CT2CA st(datasetPath);
string dataset(st);
Si vous cherchez à convertir facilement entre d'autres types de chaînes, le _bstr_t
serait plus approprié? Il prend en charge les conversions entre char
, wchar_t
et BSTR
.
Une approche intéressante consiste à transtyper CString
en CStringA
à l'intérieur d'un constructeur string
. Contrairement à std::string s((LPCTSTR)cs);
, cela fonctionnera même si _UNICODE
est défini. Toutefois, si tel est le cas, la conversion d'Unicode à ANSI sera effectuée. Par conséquent, la sécurité des valeurs Unicode supérieures au-delà du jeu de caractères ASCII n'est pas sûre. Cette conversion est soumise à la _CSTRING_DISABLE_NARROW_WIDE_CONVERSION
définition du préprocesseur. https://msdn.microsoft.com/en-us/library/5bzxfsea. aspx
CString s1("SomeString");
string s2((CStringA)s1);