windows - Sådan laver du en filestream læses i UTF-8 C ++

Indlæg af Hanne Mølgaard Plasc

Problem



Jeg kan med succes læse i UTF8 tegn tekstfiler ved at omdirigere input og output på terminalen og derefter bruge wcin og wcout


\_setmode(\_fileno(stdout), \_O\_U8TEXT);
\_setmode(\_fileno(stdin), \_O\_U8TEXT);


Nu vil jeg gerne kunne læse i UTF8-tekst ved hjælp af filestreams, men jeg ved ikke, hvordan man indstiller filestreams tilstand, så den kunne læse i disse tegn som jeg gjorde med stdin og stdout. Jeg har forsøgt at bruge wifstreams/wofstreams, og de læser og skriver stadig skrald i sig selv.

Bedste reference


C ++ 's <iostreams> biblioteket har ikke indbygget support til konverteringer fra en tekstkodning til en anden. Hvis du har brug for din indtastningstekst, der er konverteret fra utf-8 til et andet format (f.eks. De underliggende koder for kodningen), skal du skrive denne konvertering manuelt.


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;
        }
    }
}


Denne kode vil pålideligt konverteres fra [[korrekt kodet]] utf-8 til utf-32, som normalt er den nemmeste formular til at konvertere direkte til glyfer + tegn, men husk at kodeord ikke er tegn.


For at holde tingene i overensstemmelse med din kode, er min anbefaling, at utf-8 kodet tekst gemmes i dit program ved hjælp af std::string, og utf-32 kodet tekst gemmes som std::vector<uint32\_t>.