[ERLEDIGT] C++ und Boost, Windows 7, UTF-8 äöü Zeichen in Dateien



  • Hallo,

    ich habe folgendes Problem:

    Angenommen, ich habe zwei Textdateien,
    list_utf8.txt (UTF-8 kodiert) und
    list_ansi.txt (ANSI kodiert)

    Beide enthaltet eine einzige Zeile
    "C:\Testfile with äöü.dat"

    Diese leere Datei liegt tatsächlich in C:\Testfile with äöü.dat

    Jetzt lese ich mit Boost jeweils die list_utf8.txt und list_ansi.txt, gebe die Zeile aus und prüfe, ob die Datei existiert.

    Das ist das Ergebniss:

    (Bild)
    http://home.arcor.de/gabbafrog/ccc.png

    Beide male zeigt er die Umlaute im CMD nicht an (ist nicht so schlimm), aber er findet die Datei nicht, wenn er die UTF-8 Datei liest.

    Wie müsste man den folgenden Code ändern, damit das funktioniert?

    Danke!

    #include <iostream>
    #include <boost/filesystem.hpp>
    #include <boost/filesystem/fstream.hpp>
    #include <boost/algorithm/string/predicate.hpp>
    
    using namespace std;
    using namespace boost::filesystem;
    
    int main(int argc, char* argv[])
    {
        path p_list_utf ("C:\\list_utf8.txt");
        boost::filesystem::ifstream inFileUTF(p_list_utf);
        while (inFileUTF)
        {
            string s;
            getline(inFileUTF,s);
            if (inFileUTF)
            {
                cout << p_list_utf << endl << s << endl;
                if ( exists(s) )
                {
                    cout << "File exists!" << endl;
                }
                else
                {
                    cout << "File DOES NOT exist!" << endl;
                }
            }
        }
    
        path p_list_ansi ("C:\\list_ansi.txt");
        boost::filesystem::ifstream inFileANSI(p_list_ansi);
        while (inFileANSI)
        {
            string s;
            getline(inFileANSI,s);
            if (inFileANSI)
            {
                cout << p_list_ansi << endl << s << endl;
                if ( exists(s) )
                {
                    cout << "File exists!" << endl;
                }
                else
                {
                    cout << "File DOES NOT exist!" << endl;
                }
            }
        }
    
        return 0;
    }
    

    //edit:
    Jemand hat hier http://www.cplusplus.com/forum/general/91774/ eine sehr schöne Lösung für das Problem beschrieben.



  • Willkommen in der Coepage-Hölle 😉 Ich bin mir nicht sicher, wie weit boost.filesystem mit UTF8 fertig wird, oder ob es unter Windows mit deren passenden Codierungen gefüttert werden muss. Schau dir auf jeden Fall mal http://utf8everywhere.org/ an, um eine Ahnung zu bekommen, in welches Fallensystem du da getreten bist 😉



  • For Windows-like implementations, including MinGW, path::value_type is wchar_t. The default imbued locale provides a codecvt facet that invokes Windows MultiByteToWideChar or WideCharToMultiByte API with a codepage of CP_THREAD_ACP if Windows AreFileApisANSI()is true, otherwise codepage CP_OEMCP. [Rationale: this is the current behavior of C and C++ programs that perform file operations using narrow character string to identify paths. Changing this in the Filesystem library would be too surprising, particularly where user input is involved. -- end rationale]

    du musst boost::filesystem "nur" dazu bringen, die konvertierung von char zu wchar_t über die normale codecvt zu nutzen, sondern ne eigene die das 1 byte format (char) als utf8 spezifiziert, und nicht als iso_xxxx

    Ciao ...



  • Hallo,

    ich habe oben mein Problem noch einmal konkretisiert, bitte um Hilfe.

    @RHBaum
    Ich verstehe deine Antwort leider nicht, kannst du das etwas "verständlicher" schreiben? Danke 🙂



  • @gubbel
    Woher soll der std::string wo du die Zeilen reinliest denn wissen dass es einmal ein UTF-8 und einmal ein CP-1252 String ist?
    Und wenn es der std::string schon nicht mehr weiss, wie soll es dann exists() wissen?



  • Wie kann ich dem "string" / boost denn sagen, dass es sich um ein UTF-8 Zeichensatz handelt?



  • Dem String kannst du das gar nicht sagen, der hat nämlich gar keinen Platz für diese Information.

    Der Boost.Filesystem vermutlich auch nicht. Das kannst du aber in der Boost.Filesystem Doku nachlesen.



  • gubbel schrieb:

    //edit:
    Jemand hat hier http://www.cplusplus.com/forum/general/91774/ eine sehr schöne Lösung für das Problem beschrieben.

    in dem verlinkten Beitrag gibt es LINUX und eine Windows Implementierung. die Frage ist nun, ob man das mit boost::locale (ab boost 1.48) auch plattformunabh. hinbekommt
    http://www.boost.org/doc/libs/1_52_0/libs/locale/doc/html/charset_handling.html

    zu der verlinkten LINUX Implementierung ist noch zu sagen, daß sie wohl nur funktioniert, wenn auf dem System auch die Locales "en_US.utf8" und "en_US.iso88591" installiert sind. auf einigen Systemen gibt es nur "de_DE.utf8" und sonst nichts weiter

    in der C++ Localization library kann man zwar zwischen UTF-8 und UTF-16 konvertieren, aber wohl nicht zwischen UTF-8 und Latin1
    http://en.cppreference.com/w/cpp/locale



  • Hihi.
    Ich wollte gerade schreiben dass UTF-8 <-> Latin-I eh primitiv ist.
    Dann ist mir noch rechtzeitig eingefallen dass bloss UTF-16 <-> Latin-I primitiv ist (bzw. auch UTF-32 <-> Latin-I). Und das auch nur, wenn der UTF-16 String in der passenden Normalform vorliegt.

    Eieiei, alles doch nicht sooo einfach 🙂



  • Mit Qt geht das ganz einfach. QString::fromUtf8, toUft8, fromLatin1, toLatin1...



  • die Umrechnung Latin1<->Unicode ist sehr einfach, selbst Windows-1252<->Unicode ist noch rel. einfach, siehe Weblinks im Wikipedia Artikel
    http://de.wikipedia.org/wiki/ISO_8859-1#Weblinks

    die Umrechnung Unicode<->UTF-8 ist auch einfach, siehe
    http://de.wikipedia.org/wiki/UTF-8#Kodierung

    ähnlich Unicode<->UTF-16
    http://de.wikipedia.org/wiki/UTF-16#Kodierung

    wenn man nur mit Latin1, Windows-1252 und UTF-8/16/32 arbeitet, braucht man so schwere Geschütze wie boost::locale oder ICU library eigentlich nicht


Anmelden zum Antworten