Как я могу cin и cout какой-нибудь текст в unicode?

151
21

Я прошу фрагмент кода, который содержит текст в unicode, объединяет другой юникод с первым текстом юникода и результатом cout.


P.S. Этот код поможет мне решить еще одну проблему с unicode. Но прежде, чем сделать ключевую вещь, я должен выполнить то, что я прошу.


ADDED: BTW Я не могу записать в командной строке любой символ Юникода при запуске исполняемого файла. Как я должен это делать?

спросил(а) 2021-01-19T16:31:36+03:00 2 месяца, 3 недели назад
1
Решение
131

В зависимости от того, какой тип юникода вы имеете в виду. Я предполагаю, что вы имеете в виду, что вы просто работаете с std::wstring. В этом случае используйте std::wcin и std::wcout.

Для преобразования между кодировками вы можете использовать ваши функции ОС, например, для Win32: WideCharToMultiByte, MultiByteToWideChar или вы можете использовать библиотеку, например libiconv

ответил(а) 2021-01-19T16:31:36+03:00 2 месяца, 3 недели назад
114

У меня была аналогичная проблема в прошлом, в моем случае imbue и sync_with_stdio сделал трюк. Попробуйте следующее:


#include <iostream>
#include <locale>
#include <string>

using namespace std;

int main() {
ios_base::sync_with_stdio(false);
wcin.imbue(locale("en_US.UTF-8"));
wcout.imbue(locale("en_US.UTF-8"));

wstring s;
wstring t(L" la Polynésie française");

wcin >> s;
wcout << s << t << endl;
return 0;
}

ответил(а) 2021-01-19T16:31:36+03:00 2 месяца, 3 недели назад
107

Вот пример, который показывает четыре разных метода, из которых работают только третий (C conio) и четвертый (собственный Windows API) (но только если stdin/stdout не перенаправлены). Обратите внимание, что вам по-прежнему нужен шрифт, содержащий символ, который вы хотите показать (Lucida Console поддерживает по крайней мере греческий и кириллический). Обратите внимание, что все здесь совершенно не переносимо, просто нет портативного способа ввода/вывода строк Unicode на терминале.


#ifndef UNICODE
#define UNICODE
#endif

#ifndef _UNICODE
#define _UNICODE
#endif

#define STRICT
#define NOMINMAX
#define WIN32_LEAN_AND_MEAN

#include <iostream>
#include <string>
#include <cstdlib>
#include <cstdio>

#include <conio.h>
#include <windows.h>

void testIostream();
void testStdio();
void testConio();
void testWindows();

int wmain() {
testIostream();
testStdio();
testConio();
testWindows();
std::system("pause");
}

void testIostream() {
std::wstring first, second;
std::getline(std::wcin, first);
if (!std::wcin.good()) return;
std::getline(std::wcin, second);
if (!std::wcin.good()) return;
std::wcout << first << second << std::endl;
}

void testStdio() {
wchar_t buffer[0x1000];
if (!_getws_s(buffer)) return;
const std::wstring first = buffer;
if (!_getws_s(buffer)) return;
const std::wstring second = buffer;
const std::wstring result = first + second;
_putws(result.c_str());
}

void testConio() {
wchar_t buffer[0x1000];
std::size_t numRead = 0;
if (_cgetws_s(buffer, &numRead)) return;
const std::wstring first(buffer, numRead);
if (_cgetws_s(buffer, &numRead)) return;
const std::wstring second(buffer, numRead);
const std::wstring result = first + second + L'\n';
_cputws(result.c_str());
}

void testWindows() {
const HANDLE stdIn = GetStdHandle(STD_INPUT_HANDLE);
WCHAR buffer[0x1000];
DWORD numRead = 0;
if (!ReadConsoleW(stdIn, buffer, sizeof buffer, &numRead, NULL)) return;
const std::wstring first(buffer, numRead - 2);
if (!ReadConsoleW(stdIn, buffer, sizeof buffer, &numRead, NULL)) return;
const std::wstring second(buffer, numRead);
const std::wstring result = first + second;
const HANDLE stdOut = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD numWritten = 0;
WriteConsoleW(stdOut, result.c_str(), result.size(), &numWritten, NULL);
}

    Изменить 1. Я добавил метод, основанный на conio.
    Изменить 2. Я немного перепутал с _O_U16TEXT, как описано в блоге Майкла Каплана, но, похоже, только wgets интерпретировал (8-разрядные) данные из ReadFile как UTF-16. Я проведу это немного позже в выходные.

ответил(а) 2021-01-19T16:31:36+03:00 2 месяца, 3 недели назад
44

Если у вас есть фактический текст (т.е. строка логических символов), тогда вместо этого вставьте в широкие потоки. Широкие потоки будут автоматически кодировать ваши символы в соответствии с битами, ожидаемыми кодировкой локали. (И если вместо этого вы кодировали биты, потоки будут декодировать биты, а затем перекодировать их в соответствии с локалью.)


Существует меньшее решение, если вы знаете, что у вас есть кодированные в UTF биты (т.е. массив бит, предназначенный для декодирования в строку логических символов) И вы ЗНАЕТ, что цель выходного потока ожидает, что тот же бит -формат, тогда вы можете пропустить шаги декодирования и повторного кодирования и записать() биты как есть. Это работает только тогда, когда вы знаете, что обе стороны используют один и тот же формат кодирования, что может иметь место для небольших утилит, которые не предназначены для связи с процессами в других локалях.

ответил(а) 2021-01-19T16:31:36+03:00 2 месяца, 3 недели назад
-4

Это зависит от ОС. Если ваша ОС понимает, вы можете просто отправить ее последовательности UTF-8.

ответил(а) 2021-01-19T16:31:36+03:00 2 месяца, 3 недели назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема