Как заставить файловый поток читать в UTF-8 C ++ - PullRequest
0 голосов
/ 29 мая 2018

Я могу успешно читать в текстовых файлах символов UTF8, перенаправляя ввод и вывод на терминале, а затем используя wcin и wcout

_setmode(_fileno(stdout), _O_U8TEXT);
_setmode(_fileno(stdin), _O_U8TEXT);

Теперь я хотел бы иметь возможность читать в тексте UTF8используя файловые потоки, но я не знаю, как установить режим файловых потоков, чтобы он мог читать эти символы, как я делал с stdin и stdout.Я пытался использовать wifstreams / wofstreams, и те, кто все еще читает и пишут мусор, сами по себе.

1 Ответ

0 голосов
/ 29 мая 2018
Библиотека

C ++ <iostreams> не имеет встроенной поддержки для преобразования из одной кодировки текста в другую.Если вам нужно, чтобы ваш входной текст был преобразован из utf-8 в другой формат (скажем, например, базовые кодовые точки кодировки), вам нужно написать это преобразование вручную.

std::string data;
std::ifstream in("utf8.txt");
in.seekg(0, std::ios::end);
auto size = in.tellg();
in.seekg(0, std::ios::beg);
data.resize(size);
in.read(data.data(), size);
//data now contains the entire contents of the file

uint32_t partial_codepoint = 0;
unsigned num_of_bytes = 0;
std::vector<uint32_t> codepoints;
for(char c : data) {
    uint8_t byte = uint8_t(c);
    if(byte < 128) {
        //Character is just a basic ascii character, so we'll just set that as the codepoint value
        codepoints.push_back(byte);
        if(num_of_bytes > 0) {
            //Data was malformed: error handling?
            //Codepoint abruptly ended
        }
    } else {
        //Character is part of multi-byte encoding
        if(partial_codepoint) {
            //We've already begun storing the codepoint
            if((byte >> 6) != 0b10) {
                //Data was malformed: error handling?
                //Codepoint abruptly ended
            }
            partial_codepoint = (partial_codepoint << 6) | (0b0011'1111 & byte);
            num_of_bytes--;
            if(num_of_bytes == 0) {
                codepoints.emplace_back(partial_codepoint);
                partial_codepoint = 0;
            }
        } else {
            //Beginning of new codepoint
            if((byte >> 6) == 0b10) {
                //Data was malformed: error handling?
                //Codepoint did not have proper beginning
            }
            while(byte & 0b1000'0000) {
                num_of_bytes++;
                byte = byte << 1;
            }
            partial_codepoint = byte >> num_of_bytes;
        }
    }
}

Этот код будетнадежно конвертировать из [правильно закодированного] utf-8 в utf-32, который обычно является самой простой формой для непосредственного преобразования в глифы + символы, хотя помните, что кодовые точки не являются символами .

Чтобы все было согласованно в вашем коде, я рекомендую, чтобы кодированный в utf-8 текст сохранялся в вашей программе с использованием std::string, а кодированный в utf-32 текст - как std::vector<uint32_t>.

...