Как я могу cin и cout некоторый текст Unicode? - PullRequest
12 голосов
/ 09 июля 2010

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

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

ДОБАВЛЕНО: Кстати, я не могу написать в командной строке любой символ Unicode, когда я запускаю исполняемый файл. Как мне это сделать?

Ответы [ 5 ]

8 голосов
/ 09 июля 2010

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

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

7 голосов
/ 09 июля 2010

У меня была похожая проблема в прошлом, в моем случае 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;
}
6 голосов
/ 10 июля 2010

Вот пример, который показывает четыре различных метода, из которых работают только третий (C conio) и четвертый (собственный API Windows) (но только если 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.
  • Edit 2 : я немного поиграл с _O_U16TEXT, как описано в блоге Майкла Каплана, но, похоже, только wgetsинтерпретировать (8-битные) данные из ReadFile как UTF-16.Я исследую это немного подробнее в выходные.
0 голосов
/ 09 июля 2010

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

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

0 голосов
/ 09 июля 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...