Можно ли унифицировать поведение std :: wstring в VSVC и GCC? - PullRequest
0 голосов
/ 27 февраля 2019

Вот небольшой код, который читает строку из файла UFT-8:

#include <iostream>
#include <io.h>
#include <fcntl.h>
#include <locale>
#include <fstream>
#include <codecvt>

int main()
{
    _setmode(_fileno(stdout), _O_U8TEXT);

    auto inputFileStream = std::wifstream("input.txt");
    const auto utf8Locale = std::locale(std::locale(), new std::codecvt_utf8<wchar_t>());
    inputFileStream.imbue(utf8Locale);

    std::wstring line;
    std::getline(inputFileStream, line);
    std::wcout << line << std::endl;

    inputFileStream.close();
    return 0;
}

Когда я собираю его с помощью компилятора Visual Studio Visual C ++, я получаю следующий результат:

test τεστ тест

, как и ожидалось.

Когда я использую MinGW с компилятором GCC, я получил

琀 攀 猀 琀 쐃딃101 䈄 㔄 䄄 䈄

Как вы понимаете, это не ожидаемый результат.

  1. Существует ли какой-либо простой способ исправить выход для GCCк ожидаемой строке?

ИЛИ

Существует ли какой-либо простой способ использования UTF-8 для MSVC и GCC?

Ответ (спасибо за Игорь Тандетник и Реми Лебо ): Кажется, мы должны явно указать режим с прямым порядком байтов, потому что MSVC и GCC имеют разные значения по умолчанию.Поэтому следует использовать

new std::codecvt_utf8<wchar_t, 0x10ffff, std::little_endian>()

.

Фиксированный код:

#include <iostream>
#include <io.h>
#include <fcntl.h>
#include <locale>
#include <fstream>
#include <codecvt>

int main()
{
    _setmode(_fileno(stdout), _O_U8TEXT);

    auto inputFileStream = std::wifstream("input.txt");
    const auto utf8Locale = std::locale(std::locale(), new std::codecvt_utf8<wchar_t, 0x10ffff, std::little_endian>());
    inputFileStream.imbue(utf8Locale);

    std::wstring line;
    std::getline(inputFileStream, line);
    std::wcout << line << std::endl;

    inputFileStream.close();
    return 0;
}

1 Ответ

0 голосов
/ 27 февраля 2019

Для вашего второго вопроса, один вариант - ограничить использование вещей с префиксом utf16 и std::w случаями, когда вам нужно обмениваться строками в кодировке utf16 с операционной системой.Это происходит, когда вы получаете аргументы в wmain, открываете файл с помощью _wfopen, вызываете функцию Windows API и т. Д. В противном случае вы можете хранить, получать от пользователя и возвращать пользователю строки utf8, используя тип char (char*, std::string и т. Д.).Преобразование между utf8 и utf16 может быть выполнено с MultiByteToWideChar и WideCharToMultiByte, минуя запаздывающую кодировку api c ++.Место, где это не работает, - консольный ввод / вывод.В целом, вы можете вывести на консоль utf8, если пользователь установит chcp 65001 и шрифт ttf.По крайней мере, в Windows 7 вам также нужно будет убедиться, что символ не разделен между двумя вызовами записи, иначе он не будет печататься правильно (это также означает, что вы не можете использовать std::cout, потому что msvcrt будет вызывать putc для каждого байтаотдельно, и вам нужно будет использовать puts, fprintf и т. д.);Я слышал, что это было исправлено в Windows 10, но не могу подтвердить.Насколько я знаю, чтение utf8 из консоли с помощью файла api не работает;если вы хотите этого, вам нужно обнаружить, что stdin подключен к консоли, и использовать вместо него консольный API.

...