2008-11-03 12 views
63

CString es bastante útil, mientras que std::string es más compatible con el contenedor STL. Estoy usando hash_map. Sin embargo, hash_map no admite CString como clave, por lo que quiero convertir CString en std::string.Cómo convertir CString y :: std :: string :: std :: wstring entre sí?

Escribir una función de hash CString parece tomar mucho tiempo.

CString -----> std::string 

¿Cómo puedo hacer esto?

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

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

Am I right?


EDIT:

Aquí hay más preguntas:

¿Cómo puedo convertir wstring, CString el uno al otro?

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

¿Hay alguna problema?

¿Cómo puedo convertir std::wstring, std::string entre sí?

+3

No haría esto ... ¿Usar dos tipos de cadenas diferentes es suficientemente malo, pero tener que convertir cada vez que hace algo con un mapa? Suena terrible. Simplemente sea consistente y use std :: string. Si por alguna razón realmente crees que CString es mejor, entonces define una función hash para que tu hash_map pueda usarlo, esto es mucho mejor que duplicar la confusión en tu código. – GManNickG

+2

En realidad, si todo el código está escrito por mí, será coherente, pero hay algunos proyectos de fuente abierta, como sqlite de libre utilización. No puedo modificar el código. – user25749

Respuesta

78

Según CodeGuru:

CString-std::string:

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

PERO:std::string no siempre se puede construir a partir de un LPCTSTR. es decir, el código fallará para las construcciones UNICODE.

Como std::string puede construir sólo desde LPSTR/LPCSTR, un programador que utiliza 7.x VC++ o mejor pueden utilizar clases de conversión tales como CT2CA como intermediario.

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 to CString: (De Visual Studio's CString FAQs...)

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

CStringT puede construir a partir de cadenas de caracteres o ambos de caracteres anchos. es decir, puede convertir de char* (es decir, LPSTR) o de wchar_t* (LPWSTR).

En otras palabras, char-especialización (de CStringT), es decir, CStringA, wchar_t -specilization CStringW, y TCHAR -Especialización CString se puede construir de cualquiera char o de caracteres anchos, terminada en nulo (null de terminación es muy importante aquí) fuentes de cadena.
Althoug IInspectable modifica el "nulo de terminación" parte in the comments:

NUL-terminación no se requiere.
CStringT tiene constructores de conversión que toman un argumento de longitud explícita. Esto también significa que puede construir objetos CStringT desde objetos std::string con caracteres incrustados NUL.

+2

Errr ... de nada :) Gracias a Siddhartha Rao por las explicaciones detalladas. – VonC

+0

El último párrafo no es del todo correcto. La terminación 'NUL' no es obligatoria. ['CStringT'] (http://msdn.microsoft.com/en-us/library/cws1zdt8.aspx) tiene constructores de conversión que toman un argumento de longitud explícita. Esto también significa que puede construir objetos 'CStringT' a partir de objetos' std :: string' con caracteres incrustados 'NUL'. – IInspectable

+0

@IInspectable buen punto. He incluido su comentario en la respuesta para una mayor visibilidad. – VonC

33

Resuelva que mediante el uso std::basic_string<TCHAR> en lugar de std::string y que debería funcionar bien independientemente de la configuración de caracteres.

+2

Este método es más simple – user25749

+5

Me gusta typedef que por conveniencia y familiaridad: 'typedef std :: basic_string tstring' –

-1

Si está buscando convertir fácilmente entre otros tipos de cadenas, quizás la clase _bstr_t sería más apropiada? Es compatible con converstion entre char, wchar_t y BSTR.

+1

-1' CString' ya realiza todas las conversiones que usted nombre. Y lo hizo hace 3 años también. No tiene sentido sugerir un tipo que sea para uso en entornos COM. – IInspectable

4

Si quieres algo más similar a C++, esto es lo que uso. Aunque depende de Boost, eso es solo por excepciones. Puede eliminar fácilmente aquellos que lo dejen para que dependan únicamente de la llamada a la API Win32 de WideCharToMultiByte().

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

Es más eficiente para convertir CString-std::string usando la conversión, donde se especifica la longitud.

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

En lazo cerrado, esto mejora significativamente el rendimiento.

+1

Recibí un error al usar esto: 'no puedo convertir el parámetro 1 de 'CString' a 'const std :: basic_string <_Elem, _Traits, _Alloc> &' ' –

1

funciona para mí:

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

Este es un seguimiento a la respuesta de Sal, donde él/ella proporcionó la solución:

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

Esto es útil también cuando se convierte un atípico C -String a std :: string

Un caso de uso para mí era tener una matriz de caracteres preasignada (como C-String), pero no está terminada en NUL. (es decir, resumen de SHA). La sintaxis anterior me permite especificar la longitud del resumen SHA de la matriz char de modo que std :: string no tenga que buscar el carácter terminante NUL, que puede estar o no allí.

Tales como:

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

Quizás sería mejor si editara la respuesta de Sal con su enmienda adjunta o comentó la respuesta de Sal? – Kmeixner

+0

Lo intenté ... pero stackoverflow no me ha otorgado la capacidad de hacer y editar. – Neil

1

Esto funciona bien:

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

Todas las otras respuestas no se refirió exactamente lo que estaba buscando, que era convertir CString sobre la marcha en lugar de almacenar el resultado en una variable.

La solución es similar a la anterior, pero necesitamos un paso más para crear una instancia de un objeto sin nombre. Estoy ilustrando con un ejemplo. Aquí está mi función que necesita std::string pero tengo 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; 
} 

¿Cómo llamarlo cuando tiene un CString?

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

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

Tenga en cuenta que la última línea no es un encasillado directa, sino que están creando una std::string objeto sin nombre y abastecer el CString a través de su constructor.

0

¿Por qué no simplemente emitir desde CString hasta CStringA dentro de un constructor string?

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