Como converter CString e :: std :: string :: std :: wstring para o outro?
Pergunta
CString
é bastante útil, enquanto std::string
é mais compatível com o recipiente STL.
Eu estou usando hash_map
. No entanto, hash_map
não suporta CString
como chave, então eu quero CString
converter em std::string
.
Escrevendo uma função CString
de hash parece ter um monte de tempo.
CString -----> std::string
Como posso fazer isso?
std::string -----> CString:
inline CString toCString(std::string const& str)
{
return CString(str.c_str());
}
Am I certo?
EDIT:
Aqui estão mais perguntas:
Como posso converter wstring
, CString
entre si? ??
//wstring -> CString,
std::wstring src;
CString result(src.c_str());
//CString->wstring.
CString src;
::std::wstring des(src.GetString());
Existe qualquer problema?
Como posso converter std::wstring
, std::string
entre si? ??
Solução
De acordo com a CodeGuru :
CString
para std::string
:
CString cs("Hello");
std::string s((LPCTSTR)cs);
MAS: std::string
nem sempre pode construir a partir de um LPCTSTR
. ou seja, o código irá falhar para Unicode cria.
Como std::string
pode construir somente a partir LPSTR
/ LPCSTR
, um programador que utiliza 7.x VC ++ ou melhor pode utilizar classes de conversão tais como CT2CA
como intermediário.
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
para CString
: (de Visual Studio CString FAQs ... )
std::string s("Hello");
CString cs(s.c_str());
CStringT
pode construir de ambos os caracteres ou de caracteres largos strings. isto é, pode converter de char*
(isto é LPSTR
) ou a partir de wchar_t*
(LPWSTR
).
Em outras palavras, char-especialização (de CStringT
) ou seja CStringA
, wchar_t
CStringW
-specilization, e TCHAR
CString
-especialização pode ser construído a partir de qualquer char
ou de caracteres largos, terminada nula (null-término é muito importante aqui) fontes de cordas.
Althoug IInspectable altera parte "nulo-rescisão" nos comentários :?
NUL-terminação não é necessária .
CStringT
tem construtores de conversão que levam um argumento comprimento explícito. Isto também significa que você pode construir objetosCStringT
de objetosstd::string
com personagensNUL
incorporados.
Outras dicas
Solve que usando std::basic_string<TCHAR>
vez de std::string
e ele deve funcionar bem, independentemente da sua definição dos caracteres.
É mais eficiente para converter CString
para std::string
usando a conversão onde o comprimento é especificado.
CString someStr("Hello how are you");
std::string std(somStr, someStr.GetLength());
No circuito apertado este faz uma melhoria significativa do desempenho.
Se você quiser algo mais C ++ - como, este é o que eu uso. Embora depende Boost, que é apenas para exceções. Você pode facilmente remover os deixando-a depender apenas do STL ea WideCharToMultiByte()
chamada de 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);
}
(Desde VS2012 ... e pelo menos até VS2017 v15.8.1)
Uma vez que é um projeto MFC e CString é uma classe MFC, MS fornece uma Nota Técnica TN059: Usando MFC MBCS / Unicode macros de conversão e genérico conversão macros:
A2CW (LPCSTR) -> (LPCWSTR)
A2W (LPCSTR) -> (LPWSTR)
W2CA (LPCWSTR) -> (LPCSTR)
W2A (LPCWSTR) -> (LPSTR)
Use:
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" **
}
-
Notas de rodapé:
(1) Para a conversão-macros para ter espaço para armazenar o comprimento temporário, é necessário declarar uma variável local chamada _convert
que faz isso em cada função que usa as macros de conversão. Isso é feito chamando o macro USES_CONVERSION
. No código VS2017 MFC (Atlconv.h) parece que isso:
#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
Este é um acompanhamento para a resposta do Sal, onde ele / ela forneceu a solução:
CString someStr("Hello how are you");
std::string std(somStr, someStr.GetLength());
Isto é útil também ao converter um não-típico C-String para um std :: string
Um caso para mim estava tendo uma matriz de char pré-alocada (como C-String) o uso, mas não é NUL encerrado. (Isto é, SHA digestão). A sintaxe acima me permite especificar o comprimento da SHA digest da matriz de char para que std :: string não tem que olhar para o caractere de terminação NUL, que pode ou não estar lá.
Tais como:
unsigned char hashResult[SHA_DIGEST_LENGTH];
auto value = std::string(reinterpret_cast<char*>hashResult, SHA_DIGEST_LENGTH);
Esta multa funciona:
//Convert CString to std::string
inline std::string to_string(const CString& cst)
{
return CT2A(cst.GetString());
}
a partir deste post (obrigado Mark Ransom )
Converter CString para string (VC6)
Eu testei isso e ele funciona muito bem.
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;
}
funciona para mim:
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();
}
Todas as outras respostas não chegou a abordar o que eu estava procurando, que era converter CString
na mosca ao invés de armazenar o resultado em uma variável.
A solução é semelhante ao anterior, mas precisamos de mais um passo para instanciar um objeto sem nome. Estou ilustrando com um exemplo. Aqui é a minha função que precisa std::string
mas tenho 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;
}
Como chamá-lo quando você tem um CString
?
std::string firstName = "First";
CString lastName = _T("Last");
writeLog( firstName + ", " + std::string( CT2A( lastName ) ) );
Note que a última linha não é um typecast direta, mas estamos criando um objeto sem nome std::string
e fornecer o CString
via seu construtor.
Existe qualquer problema?
Há várias questões:
-
CString
é uma especialização de modelo de CStringT . Dependendo do BaseType que descreve o tipo de caractere, há duas especializações concretas:.CStringA
(usandochar
) eCStringW
(usandowchar_t
) - Enquanto
wchar_t
no Windows é ubíqua usado para armazenar UTF-16 unidades de código codificado, usandochar
é ambíguo. O último comumente armazena ANSI codificado personagens, mas também pode armazenar ASCII, UTF-8, ou mesmo dados binários. - Não sabemos a codificação de caracteres (ou tipo personagem ainda) de
CString
(que é controlada através do símbolo pré-processador_UNICODE
), tornando a questão ambígua. Nós também não sabemos o caractere desejado codificação destd::string
. - Conversão entre Unicode e ANSI é inerentemente com perdas:. Codificação ANSI podem representar apenas um subconjunto do conjunto de caracteres Unicode
Para tratar dessas questões, eu vou assumir que wchar_t
irá armazenar UTF-16 unidades de código codificados e char
vai realizar seqüências de UTF-8 octeto. Essa é a única escolha razoável você pode fazer para garantir que as cordas de origem e destino manter a mesma informação, sem limitar a solução para um subconjunto dos domínios de origem ou de destino.
Os seguintes implementações converter entre CStringA
/ CStringW
e std::wstring
/ std::string
mapeamento de UTF-8 para UTF-16 e 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 };
}
O restante duas funções construção C ++ objectos cordas de cordas MFC, deixando o que codifica inalterada. Note-se que enquanto as funções anteriores não pode lidar com caracteres NUL embutidos, essas funções são imunes a isso.
#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() };
}
Você pode usar CT2CA
CString datasetPath;
CT2CA st(datasetPath);
string dataset(st);
Se você estiver olhando para converter facilmente entre outros tipos de cordas, talvez o _bstr_t
classe seria mais apropriado? Ele suporta converstion entre char
, wchar_t
e BSTR
.
Uma abordagem interessante é CString
elenco para CStringA
dentro de um construtor string
. Ao contrário std::string s((LPCTSTR)cs);
isso vai funcionar mesmo se _UNICODE
está definida. No entanto, se for esse o caso, isso irá executar a conversão de Unicode para ANSI, por isso não é seguro para valores Unicode mais elevados para além do conjunto de caracteres ASCII. Tal conversão está sujeito à definição _CSTRING_DISABLE_NARROW_WIDE_CONVERSION
pré-processador. https://msdn.microsoft.com/en-us/library/5bzxfsea. aspx
CString s1("SomeString");
string s2((CStringA)s1);