Страница 2 из 4

Re: Не получается приведение

Добавлено: 09 апр 2014, 14:27
WinMain
И чем же это макросы лучше функций? Да ещё нуль-терминальная строка в интерфейсе.
Ну хотя бы тем, что облегчат тебе работу и в значительной степени уберегут от лишних ошибок в коде.
А чем тебе не нравится константная null-terminated строка в формате UNICODE на входе функции?

Re: Не получается приведение

Добавлено: 09 апр 2014, 14:33
Сионист
Romeo писал(а):Нет, не завёрнут. Для длины отдельное поле класса предусмотрено.
Сам себе противоречишь.

Re: Не получается приведение

Добавлено: 09 апр 2014, 14:38
Сионист
WinMain писал(а):Ну хотя бы тем, что облегчат тебе работу и в значительной степени уберегут от лишних ошибок в коде.
Облегчат работу как раз функции, а макросов не зря во всех книгах, где они упоминаются, рекомендуют избегать из-за того, что они не знают об областях видимости.
WinMain писал(а):А чем тебе не нравится константная null-terminated строка в формате UNICODE на входе функции?
Тем, что мне придётся таскать c_str по всему тексту для каждого вызова. И совсем другое дело, если приведение к нуль-терминальной завернуто в саму функцию приведения к std::string. В этом случае достаточно вызвать саму функцию и передать ей строку для преобразования.

Re: Не получается приведение

Добавлено: 09 апр 2014, 14:42
Сионист
Romeo писал(а):Как решить проблему? Либо вернуть наружу перекодированный массив по поинтеру (и не забыть ему сделать delete [] после выводы в файл), либо возвращать std::vector<char>, воспользовавшись для создания его объекта конструтором, принимающим два итератора. Второй подход более красив, так как позволяет избежать потенциального мемори лика зазеваашемуся программисту, вызывающему твою функцию, но зато требует чуть большей сноровки.
Ога. И потом мучаться с сохранением в файл. Ну очень решение. Причём, если в UTF-8 будут лишние ноли, то вывод циклом обеспечен и нуль=терминалу.

Re: Не получается приведение

Добавлено: 09 апр 2014, 14:44
Сионист
Romeo писал(а):Повторюсь, ты использовал std::string, а не что-то другое. И с ним UTF-8 работать не будет.
И кто же запретит std::string юзать за строку байтов? А в байтах коды символов и части длинных кодов символов. Стринг то о кодировках не знает.

Re: Не получается приведение

Добавлено: 09 апр 2014, 15:13
Romeo
Сам себе противоречишь.
Нет, не противоречу. Ты просто пытаешься читать между строк и додумывать за меня то, чего я не говорил. Выражение "внутри была" не говорит о том, что в классе, кроме СИ строки больше ничего нет.
Ога. И потом мучаться с сохранением в файл. Ну очень решение. Причём, если в UTF-8 будут лишние ноли, то вывод циклом обеспечен и нуль=терминалу.
Это уже как заиплементишь. Ты ведь умный, и должен догадаться вывести size() - 1.
Облегчат работу как раз функции, а макросов не зря во всех книгах, где они упоминаются, рекомендуют избегать из-за того, что они не знают об областях видимости.
Не путай. В книгах рекомендуют не писать свои макросы. Но если это уже часть библиотеки, причём ни какой-то там, а Microsoft, то никто не мешает тебе использовать макрос, тем более, если он удобен.
И кто же запретит std::string юзать за строку байтов? А в байтах коды символов и части длинных кодов символов. Стринг то о кодировках не знает.
Стринг о кодировках дейстивильного ничего не знает, но если строка станет честным UTF, как в твоём первом посте, то стринг не переварит внутренние нули. Я имел ввиду только это и больше ничего. Ты же почему-то постоянно пытаешь уйти от этой простой мысли, то делая цитаты из стандарта, то начиная придираться к словам и придумывать то, чего я не говорил, или вообще вспоминаешь какую-то там TString, которую вообще не используешь в коде. Будь мужиком, просто возьми и вернись к CP_UTF8 и докажи мне, что всё будет работать с std::string, если в строке кириллица :)

Re: Не получается приведение

Добавлено: 09 апр 2014, 15:23
Сионист
Проблема решена.

Код: Выделить всё

std::string                                 WStringToUtf8                             (const
                                                                                       std::wstring                     &s                 )
{
 char        *Buffer;
 char        *p;
 size_t       i;
 size_t       BufferSize;
 std::string  Result="";
 if (!s.empty())
 {
  BufferSize=WideCharToMultiByte(CP_UTF8, 0, s.c_str(), s.length(), NULL, 0, NULL, NULL);
  Buffer=new char[BufferSize];
  if (Buffer!=NULL)
  {
   WideCharToMultiByte(CP_UTF8, 0, s.c_str(), s.length(), Buffer, BufferSize, NULL, NULL);
   for (i=0, p=Buffer; i<BufferSize; ++i, ++p)
   {
    Result+=*p;
   }
   delete [] Buffer;
  }
 }
 return Result;
}

Re: Не получается приведение

Добавлено: 09 апр 2014, 15:24
Romeo
Не работает с кириллицей. Вместо русских букв будут вставлены усечённые до одного байта ASCII символы с неожиданным значением.

Зачем лепить костыли с циклом (причём неработающим), если можно вернуть честный вектор символов? Только ради того, чтобы не согласиться со мной? Ты пойми, я не самоутверждаюсь за счёт тебя. Я реально помочь хочу. Я тебе рассказываю, как сделать академически правильно.

Re: Не получается приведение

Добавлено: 10 апр 2014, 11:01
WinMain

Код: Выделить всё

 std::string  Result="";
 . . . . . .

   for (i=0, p=Buffer; i<BufferSize; ++i, ++p)
   {
    Result+=*p;
   }
И ты считаешь это удачным решением задачи? Если строку в виде std::string наращивать посимвольно, то это приведёт к жудким тормозам при выполнении программы. На коротких строках это может и незаметно будет, но на более длинных текстах программа будет просто умирать.
Тем, что мне придётся таскать c_str по всему тексту для каждого вызова. И совсем другое дело, если приведение к нуль-терминальной завернуто в саму функцию приведения к std::string.
Это вообще решается элементарно. Можно создать перегруженную функцию, которая на входе будет принимать строку в виде std::wstring и передавать вызов одноимённой функции, у которой на входе будет LPCWSTR. Вот как я это сделал...

Код: Выделить всё

std::string WcharToUtf8(LPCWSTR wszInputStr)
{
	USES_CONVERSION;
	LPCSTR output = W2CA_CP(wszInputStr, CP_UTF8); 
	// 
	return std::string(output);
}

std::string WcharToUtf8(const std::wstring& wInputStr)
{
	return WcharToUtf8(wInputStr.c_str());
}
Теперь одну и ту же функцию WcharToUtf8 я могу использовать как для строк LPCWSTR, так и для строк std::wstring.

Ну а теперь самое главное: проверим на практике работоспособность функции.
Если полученную на выходе строку в кодировке UTF-8 попытаться вывести на консоль, то нормально будут отображаться только латинские буквы, а вместо кириллицы получим нечитаемый текст.
Значит нужно отобразить полученный текст каким-то иным способом.
Попробуем записать его в текстовый файл в виде страницы HTML и затем открыть страницу веб-браузером...

Код: Выделить всё

LPCWSTR wszHtmlPage = 
	L"<!DOCTYPE html>"
	L"<html><head>"
    L"<meta content=\"text/html; charset=utf-8\" http-equiv=\"content-type\" />"
    L"<title>Всем привет!</title>"
	L"</head><body>"
	L"<h2>Это строка текста в кодировке UTF-8</h2>"
	L"</body></html>";

	std::string utf8 = WcharToUtf8(wszHtmlPage);
	// Запись в файл
	FILE *f = NULL;
	_tfopen_s(&f, _T("HelloUTF8.html"), _T("w"));
	if (f != NULL)
	{
		fputs(utf8.c_str(), f);
		fclose(f);
	}
При выполнении кода у меня появился файл HelloUTF8.html, в котором весь текст корректно отображается. Если кликнуть по странице правой кнопкой мыши и в контекстном меню выбрать "Просмотр кода страницы", то увидим весь наш текст, который был туда записан. Никаких лишних символов там не появилось.

Re: Не получается приведение

Добавлено: 10 апр 2014, 11:26
Romeo
WinMain писал(а):Если полученную на выходе строку в кодировке UTF-8 попытаться вывести на консоль, то нормально будут отображаться только латинские буквы, а вместо кириллицы получим нечитаемый текст.
От этого спасает SetConsoleOutputCP(1251). Если не помогло, то дополнительно проверить, что для консоли выставлен юникодный шрифт.