Как преобразовать CString и::std::string::std::wstring друг в друга?
CString
довольно удобно, в то время как std::string
более совместим с контейнером STL. я использую hash_map
, Тем не мение, hash_map
не поддерживается CString
как ключ, поэтому я хочу конвертировать CString
в std::string
,
Написание CString
хэш-функция, кажется, занимает много времени.
CString -----> std::string
Как я могу это сделать?
std::string -----> CString:
inline CString toCString(std::string const& str)
{
return CString(str.c_str());
}
Я прав?
РЕДАКТИРОВАТЬ:
Вот еще вопросы:
Как я могу конвертировать wstring
, CString
друг другу?
//wstring -> CString,
std::wstring src;
CString result(src.c_str());
//CString->wstring.
CString src;
::std::wstring des(src.GetString());
Есть ли проблемы?
Как я могу конвертировать std::wstring
, std::string
друг другу?
17 ответов
Согласно CodeGuru:
CString
в std::string
:
CString cs("Hello");
std::string s((LPCTSTR)cs);
НО: std::string
не всегда можно построить из LPCTSTR
, т.е. код не удастся для сборок UNICODE.
Как std::string
можно построить только из LPSTR
/ LPCSTR
программист, который использует VC++ 7.x или выше, может использовать классы преобразования, такие как CT2CA
в качестве посредника.
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
: (Из часто задаваемых вопросов по CString в Visual Studio...)
std::string s("Hello");
CString cs(s.c_str());
CStringT
может составлять как символьные, так и широкие символьные строки. т.е. он может конвертировать из char*
(т.е. LPSTR
) или из wchar_t*
(LPWSTR
).
Другими словами, специализация чар CStringT
) т.е. CStringA
, wchar_t
-specilization CStringW
, а также TCHAR
-specialization CString
может быть построен из любого char
или широкоформатный, завершено null (окончание null здесь очень важно) строковые источники.
Althoug IInspectable вносит поправки в часть "нулевого завершения" в комментариях:
NUL-прекращение не требуется.
CStringT
имеет конструкторы преобразования, которые принимают явный аргумент длины. Это также означает, что вы можете построитьCStringT
объекты изstd::string
объекты со встроеннымиNUL
персонажи.
Решите это с помощью std::basic_string<TCHAR>
вместо std::string
и он должен работать нормально, независимо от ваших настроек персонажа.
Это более эффективно, чтобы преобразовать CString
в std::string
используя преобразование, где указана длина.
CString someStr("Hello how are you");
std::string std(somStr, someStr.GetLength());
В тесной петле это делает значительное улучшение производительности.
Если вы хотите что-то более C++- например, это то, что я использую. Хотя это зависит от Boost, это только для исключений. Вы можете легко удалить тех, кто оставляет это, чтобы зависеть только от STL и WideCharToMultiByte()
Вызов Win32 API.
#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);
}
Есть ли проблемы?
Есть несколько вопросов:
CString
является шаблонной специализацией CStringT. В зависимости от BaseType, описывающего тип символа, есть две конкретные специализации:CStringA
(с помощьюchar
) а такжеCStringW
(с помощьюwchar_t
).- В то время как
wchar_t
в Windows повсеместно используется для хранения кодированных единиц UTF-16, используяchar
неоднозначно. Последний обычно хранит символы в кодировке ANSI, но также может хранить ASCII, UTF-8 или даже двоичные данные. - Мы не знаем кодировку символов (или даже тип символов)
CString
(который контролируется через_UNICODE
символ препроцессора), что делает вопрос неоднозначным. Мы также не знаем желаемую кодировку символовstd::string
, - Преобразование между Unicode и ANSI по своей природе является потерями: кодировка ANSI может представлять только подмножество набора символов Unicode.
Для решения этих вопросов я собираюсь предположить, что wchar_t
будет хранить кодированные единицы UTF-16 и char
будет содержать октетные последовательности UTF-8. Это единственный разумный выбор, который вы можете сделать, чтобы гарантировать, что строки источника и назначения сохраняют одну и ту же информацию, не ограничивая решение подмножеством доменов источника или назначения.
Следующие реализации преобразовывают между CStringA
/ CStringW
а также std::wstring
/ std::string
отображение от UTF-8 до UTF-16 и наоборот:
#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 };
}
Оставшиеся две функции создают строковые объекты C++ из строк MFC, оставляя кодировку без изменений. Обратите внимание, что, хотя предыдущие функции не могут справиться со встроенными символами NUL, эти функции защищены от этого.
#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() };
}
(С VS2012 ... и по крайней мере до VS2017 v15.8.1)
Поскольку это проект MFC, а CString - класс MFC, MS предоставляет Техническое примечание TN059: Использование макросов преобразования MFC /Unicode и макросов общего преобразования:
A2CW (LPCSTR) -> (LPCWSTR)
A2W (LPCSTR) -> (LPWSTR)
W2CA (LPCWSTR) -> (LPCSTR)
W2A (LPCWSTR) -> (LPSTR)
Использование:
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" **
}
-
Примечания:
(1) Чтобы в макросах преобразования было место для хранения временной длины, необходимо объявить локальную переменную с именем _convert
это делается в каждой функции, которая использует макросы преобразования. Это делается путем вызова USES_CONVERSION
макро. В коде MFC VS2017 (atlconv.h) это выглядит так:
#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
CString
есть метод,
GetString()
, который возвращает
LPCWSTR
введите, если вы используете Unicode, или
LPCSTR
иначе.
В случае Unicode вы должны передать его через
wstring
:
CString cs("Hello");
wstring ws = wstring(cs.GetString());
string s = string(ws.begin(), ws.end());
В противном случае вы можете просто преобразовать строку напрямую:
CString cs("Hello");
string s = string(cs.GetString());
Конвертировать CString to std::string
. Вы можете использовать этот формат.
std::string sText(CW2A(CSText.GetString(), CP_UTF8 ));
Из этого поста (спасибо Mark Ransom)
Конвертировать CString в строку (VC6)
Я проверил это, и он отлично работает.
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;
}
Это отлично работает:
//Convert CString to std::string
inline std::string to_string(const CString& cst)
{
return CT2A(cst.GetString());
}
Это продолжение ответа Сэла, где он / она предоставили решение:
CString someStr("Hello how are you");
std::string std(somStr, someStr.GetLength());
Это полезно также при преобразовании нестандартной C-String в std:: string
Вариант использования для меня имел предварительно выделенный массив символов (например, C-String), но он не завершен NUL. (т.е. дайджест SHA). Приведенный выше синтаксис позволяет мне указать длину дайджеста SHA массива char, так что std:: string не нужно искать завершающий символ NUL, который может быть или не быть там.
Такие как:
unsigned char hashResult[SHA_DIGEST_LENGTH];
auto value = std::string(reinterpret_cast<char*>hashResult, SHA_DIGEST_LENGTH);
Вы можете использовать CT2CA
CString datasetPath;
CT2CA st(datasetPath);
string dataset(st);
Один интересный подход состоит в том, чтобы бросить CString
в CStringA
внутри string
конструктор. В отличие от std::string s((LPCTSTR)cs);
это будет работать, даже если _UNICODE
определено. Однако в этом случае будет выполнено преобразование из Unicode в ANSI, поэтому небезопасно для более высоких значений Unicode, выходящих за пределы набора символов ASCII. Такое преобразование подлежит _CSTRING_DISABLE_NARROW_WIDE_CONVERSION
определение препроцессора. https://msdn.microsoft.com/en-us/library/5bzxfsea.aspx
CString s1("SomeString");
string s2((CStringA)s1);
Все остальные ответы не совсем соответствовали тому, что я искал, чтобы конвертировать CString
на лету, а не хранить результат в переменной.
Решение похоже на приведенное выше, но нам нужен еще один шаг для создания экземпляра безымянного объекта. Я иллюстрирую на примере. Вот моя функция, которая нуждается std::string
но у меня есть 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;
}
Как это назвать, когда у вас есть CString
?
std::string firstName = "First";
CString lastName = _T("Last");
writeLog( firstName + ", " + std::string( CT2A( lastName ) ) );
Обратите внимание, что последняя строка не является прямым типом трансляции, но мы создаем безымянный std::string
возражать и поставлять CString
через его конструктор.
Если вы хотите легко конвертировать другие типы строк, возможно, _bstr_t
класс будет более уместным? Поддерживает разговор между char
, wchar_t
а также BSTR
,
Работает для меня:
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();
}
Вы можете бросить CString
свободно к const char*
а затем назначьте его std::string
нравится:
CString cstring("MyCString");
std::string str = (const char*)cstring;