Как мне преобразовать wchar_t* в std::string?
Я изменил свой класс, чтобы использовать std::string (основываясь на полученном здесь ответе, но у меня есть функция, возвращающая wchar_t *. Как мне преобразовать его в std::string?
Я попробовал это:
std::string test = args.OptionArg();
но он говорит об ошибке C2440: "инициализация": невозможно преобразовать из "wchar_t *" в "std::basic_string<_Elem, _Traits, _Ax>"
7 ответов
Вы могли бы просто использовать wstring
и держи все в юникоде
wstring ws( args.OptionArg() );
string test( ws.begin(), ws.end() );
Вы можете преобразовать широкую строку символов в строку ASCII, используя следующую функцию:
#include <locale>
#include <sstream>
#include <string>
std::string ToNarrow( const wchar_t *s, char dfault = '?',
const std::locale& loc = std::locale() )
{
std::ostringstream stm;
while( *s != L'\0' ) {
stm << std::use_facet< std::ctype<wchar_t> >( loc ).narrow( *s++, dfault );
}
return stm.str();
}
Имейте в виду, что это просто заменит любой широкий символ, для которого эквивалентный символ ASCII не существует с dfault
параметр; он не конвертируется из UTF-16 в UTF-8. Если вы хотите конвертировать в UTF-8, используйте такую библиотеку, как ICU.
Довольно разочаровывает тот факт, что ни один из ответов на этот старый вопрос не решает проблему преобразования широких строк в строки UTF-8, что важно в средах, отличных от английского.
Вот пример кода, который работает и может быть использован в качестве подсказки для создания пользовательских преобразователей. Он основан на примере кода из примера кода на сайте cppreference.com .
#include <iostream>
#include <clocale>
#include <string>
#include <cstdlib>
#include <array>
std::string convert(const std::wstring& wstr)
{
const int BUFF_SIZE = 7;
if (MB_CUR_MAX >= BUFF_SIZE) throw std::invalid_argument("BUFF_SIZE too small");
std::string result;
bool shifts = std::wctomb(nullptr, 0); // reset the conversion state
for (const wchar_t wc : wstr)
{
std::array<char, BUFF_SIZE> buffer;
const int ret = std::wctomb(buffer.data(), wc);
if (ret < 0) throw std::invalid_argument("inconvertible wide characters in the current locale");
buffer[ret] = '\0'; // make 'buffer' contain a C-style string
result = result + std::string(buffer.data());
}
return result;
}
int main()
{
auto loc = std::setlocale(LC_ALL, "en_US.utf8"); // UTF-8
if (loc == nullptr) throw std::logic_error("failed to set locale");
std::wstring wstr = L"aąß水-扫描-€\u00df\u6c34\U0001d10b";
std::cout << convert(wstr) << "\n";
}
Это печатает, как и ожидалось:
Объяснение
- 7 кажется минимальным безопасным значением размера буфера,
BUFF_SIZE
. Сюда входит 4 как максимальное количество байтов UTF-8, кодирующих один символ; 2 для возможной «последовательности сдвига», 1 для завершающей'\0'
. -
MB_CUR_MAX
это переменная времени выполнения времени выполнения , поэтомуstatic_assert
здесь нельзя использовать - Каждый расширенный символ переводится в свой
char
представление с использованиемstd::wctomb
- Это преобразование имеет смысл только в том случае, если текущая локаль допускает многобайтовое представление символа.
- Чтобы это работало, приложение должно установить правильную локаль.
en_US.utf8
кажется достаточно универсальным (имеется на большинстве машин). В Linux доступные локали можно запросить в консоли черезlocale -a
команда.
Критика ответа, получившего наибольшее количество голосов
Самый популярный ответ,
std::wstring ws( args.OptionArg() );
std::string test( ws.begin(), ws.end() );
хорошо работает только тогда, когда широкие символы представляют собой символы ASCII, но это не то, для чего были разработаны широкие символы. В этом решении преобразованная строка содержит один символ на каждый исходный широкий символ,
ws.size() == test.size()
. Таким образом, он теряет информацию из исходной wstring и создает строки, которые нельзя интерпретировать как правильные последовательности UTF-8. Например, на моей машине строка, полученная в результате этого упрощенного преобразования «ĄŚĆII», печатается как «ZII», хотя ее размер равен 5 (а должен быть 8).
Это старый вопрос, но если это не тот случай, когда вы на самом деле ищете конверсии, а используете TCHAR от Mircosoft для создания ASCII и Unicode, вы можете вспомнить, что std::string действительно
typedef std::basic_string<char> string
Таким образом, мы могли бы определить наш собственный typedef, скажем,
#include <string>
namespace magic {
typedef std::basic_string<TCHAR> string;
}
Тогда вы могли бы использовать magic::string
с TCHAR
, LPCTSTR
, и так далее
Просто для удовольствия:-):
const wchar_t* val = L"hello mfc";
std::string test((LPCTSTR)CString(val));
Следующий код более лаконичен:
wchar_t wstr[500];
char string[500];
sprintf(string,"%ls",wstr);