[gelöst] Umlaute in QString aus stdString



  • Hallo,

    ich stehe wieder einmal vor einem Problem.
    Ich lege in meinem c++-Code .txt-Dateien an und lese sie auch später wieder in dem Code.
    Meine Qt-Gui holt sich dann die gelesenen Strings vom Code und soll sie in einem QLabel anzeigen.

    Das Problem: Umlaute werden dabei nicht korrekt dargestellt. Ich habe es schon mit

    trUtf8(QString::fromStdString(...)),
    QString::fromStdString(...).toUtf8() und
    QString::fromStdString(...).toLatin1()
    

    probiert, kein Erfolg.

    Mit QTextCodec habe ich es noch nicht versucht, weil ich nicht weiß, welche kodierung die stdStrings verwenden.

    Kann mir jemand weiterhelfen oder einen Tipp in die richtige Richtung geben? 🙂

    Ach ja, ich nutze als OS Linux.

    Viele Grüße
    Cherup



  • Deine Formulierungen sind unschön ("holt sich dann die gelesenen Strings vom Code").
    Warum nutzt du StdString, wenn du Qt nutzt?
    Bei Qt gibts zum Schreiben und Lesen die QTextStream und dort kann man mit setCodec() die Formatierung ganz einfach festlegen.

    QString::fromStdString() nutzt intern QString::fromUtf8(const char * str, int size = -1), erwartet also einen Utf8-codierten String.
    Das du danach .toUtf8 auf diesen anwendest ergibt überhaupt keinen Sinn.
    Gibt es einen Grund nicht QTextStream zu nutzen?



  • Hi,

    hast recht das hätte ich besser schreiben können 😃

    Das ganze Programm ist in "reinem" c++ geschrieben, die GUI ist nur optional und nur über eine Klasse an das restliche Programm angebunden.

    Der Grund, nicht Qt für den Daten-IO zu nutzen ist, dass ich den c++-Code und den Qt-Code , also die Logik und die GUI, getrennt voneinander halten möchte um die Möglichkeit zu haben, GUIs in anderen Sprachen anbinden zu können.

    Danke für den Hinweis, das fromStdString intern fromUtf8 nutzt, das wußte ich bisher noch nicht. Das bedeutet, dass ich den stdString vorher in UTF8 "umwandeln" muss.

    VG
    Cherup



  • Cherup schrieb:

    Danke für den Hinweis, das fromStdString intern fromUtf8 nutzt, das wußte ich bisher noch nicht. Das bedeutet, dass ich den stdString vorher in UTF8 "umwandeln" muss.

    Oder die Daten gleich in UTF8 erzeugen. Dann brauchst du beim Einlesen nichts "umwandeln"



  • Soo,

    die .txt-Dateien liegen im UTF8 vor, trotzdem werden Umlaute in der GUI nicht korrekt dargestellt.
    Ich habe festgestellt, dass das Problem schon beim einlesen auftritt, d.h. ich muss da ansetzen.

    Danke für eure Hilfe.

    Viele Grüße
    Cherup



  • Cherup schrieb:

    Soo,

    die .txt-Dateien liegen im UTF8 vor, trotzdem werden Umlaute in der GUI nicht korrekt dargestellt.
    Ich habe festgestellt, dass das Problem schon beim einlesen auftritt, d.h. ich muss da ansetzen.

    Danke für eure Hilfe.

    Viele Grüße
    Cherup

    Sicher das die Daten in der txt datei in UTF-8 vorliegen?
    (z.b. die umlaute wie z.b. ä sollte als zwei bytes in der text datei auftauchen, wenn man sich die datei in einem hex editor anschaut.
    Wenn du die daten mit einem filestream aus der stl einliest sollte keine konvertierung der daten erfolgen.



  • Ziemlich sicher.
    Ich habe die Datei mit dem Unix-Befehl file -bi getestet, dort wurde als charset UTF-8 angegeben.
    Habs mir eben auch mal in einem HEX-Editor angeschaut, ein "ö" wird als C3 B6 kodiert, was laut der Unicode/UTF8-Zeichentabelle korrekt ist.

    Der Code, um die Dateien einzulesen schaut folgendermaßen aus:

    string FileData;
    
        ifstream is(filePath.c_str()); //filePath wurde der Funktion übergeben
        FileData.assign( (istreambuf_iterator<char>(is) ),
                         (istreambuf_iterator<char>()   ) );
    
        return  FileData;
    


  • Und woher weiß ifstream bzw. string::assign das der Dateiinhalt in UTF8 codiert ist und nicht z.B. UTF16?



  • Softwaremaker schrieb:

    Und woher weiß ifstream bzw. string::assign das der Dateiinhalt in UTF8 codiert ist und nicht z.B. UTF16?

    ist dem stream in diesm falle egal, da er byteweise einliest.



  • Cherup schrieb:

    Ziemlich sicher.
    Ich habe die Datei mit dem Unix-Befehl file -bi getestet, dort wurde als charset UTF-8 angegeben.
    Habs mir eben auch mal in einem HEX-Editor angeschaut, ein "ö" wird als C3 B6 kodiert, was laut der Unicode/UTF8-Zeichentabelle korrekt ist.

    Der Code, um die Dateien einzulesen schaut folgendermaßen aus:

    string FileData;
    
        ifstream is(filePath.c_str()); //filePath wurde der Funktion übergeben
        FileData.assign( (istreambuf_iterator<char>(is) ),
                         (istreambuf_iterator<char>()   ) );
    
        return  FileData;
    

    Was ist wenn du den content in FileData wieder in eine Datei schreibst?
    Ist es dann nimmer noch utf8?
    Normalerweise sollte auch im std::string die umlaute als 2 bytes dargestellt werden. Denn AFAIK macht ein ifstream beim lesen keinerlei Änderungen an dem was es einliest (bis auf line endings konvertierungen)
    Schau dir das mal mit nem debugger an, was im std::string drinnsteht.
    Wenn da alles passt dann hast du ein problem bei der konvertierung des contents zu QString



  • Im string FileData tritt bereits der Fehler auf, da werden Umlaute nicht korrekt dargestellt.
    Wenn ich Daten aus FileData wieder in eine neue .txt-datei schreibe, bleibt es UTF8.



  • Cherup schrieb:

    Im string FileData tritt bereits der Fehler auf, da werden Umlaute nicht korrekt dargestellt.
    Wenn ich Daten aus FileData wieder in eine neue .txt-datei schreibe, bleibt es UTF8.

    Was heißt wird nicht korrekt dargestellt? Vermutlich kann dein debugger nichts mit utf-8 kodierten strings anfangen.

    Z.b. ein 'ä' wird dann unter umständen als "À" dargestellt.
    Das ist dann ein reines Darstellungsproblem.

    Für mich klingt das so als ob das einlesen funktioniert.
    Dann sollte die Konvertierung zu QString mit QString::fromUtf8/fromStdString funktionieren.



  • Tja, das würde ich auch sagen, nur funktioniert es leider nicht...

    was meinst du mit QString::fromUtf8/fromStdString, jeweils eins der beiden oder geschachtelt?
    (Läuft nur mit fromStdString, frage nur nach um das zu verstehen.)



  • string::assign macht automatisch eine UTF-8 Konvertierung? Ich denke nein. Da liegt das Problem.



  • Hmm gut möglich, nur das der Inhalt der Datei, wenn er gelesen wird und anschließend in eine neue Datei geschrieben wird, weiterhin in UTF8 bleibt.
    Wie schon geschrieben, die Datei aus der gelesen wird ist korrektes UTF8, die neue ebenfalls, ich habe bisher noch nichts an meinem Code verändert.

    Was ist die Alternative zu assign?



  • Softwaremaker schrieb:

    string::assign macht automatisch eine UTF-8 Konvertierung? Ich denke nein. Da liegt das Problem.

    Nein assign macht keinerlei konvertierung.
    Ich denke das Problem liegt aktuell nicht mehr beim einlesen des UTF8 contents in einen std::string.
    Ich denke eher das Problem liegt bei der konvertierung des std::string in einen QString.

    @Cherup: Könntest du mal ein minimalbeispiel posten, welche das Problem zeigt?



  • Sicher.

    Qt-Abschnitt:

    void MainGUI::createItem(ItemData* itemdata{
    
    QLabel DescriptionLabel = new QLabel(QString::fromStdString(itemdata->getDescription()));
    }
    

    Klasse ItemData:

    class ItemData{
    private:
        string myDescription;
    
    public:
        ItemData();
    
        string getDescription();
        void setDescription(string description);
    };
    
    string ItemData::getDescription(){
    return myDescription;
    }
    
    void ItemData::setDescription(string description){
    myDescription = description;
    }
    

    FileAccess-Klasse:

    string FileAccess::readFile(path filePath){
    //der Datentyp path kommt aus der Boost-Library
    
        string FileData;
    
        ifstream is(filePath.c_str());
        FileData.assign( (istreambuf_iterator<char>(is) ),
                         (istreambuf_iterator<char>()   ) );
    
        return  FileData;
    }
    

    Das sind die entsprechenden Code-Fragmente. Kann sein, dass ein oder zwei Schreibfehler drinstecken, habs auf die schnelle aus dem Kopf geschrieben.
    Der Ablauf ist, dass erst der Logik-Teil initialisiert wird, dann die Daten aus den Dateien gelesen und den entsprechenden Klassen und Objekten zugewiesen wird, und zum Schluss erst die GUI gebaut wird, die sich die Daten von den Objekten holt.



  • Das ist kein minimalbeispiel, welche das problem zeigt.
    Hätte wohl noch dazu schreiben sollen ein funktionierendes minimal beispiel



  • So,
    bin leider nicht eher dazu gekommen, ein Minimalbeispiel zu erstellen.
    Hättest das "funktionierend" an sich nicht dazu schreiben müssen, wußte schon, dass du das meinst, aber ich hatte keine Zeit 😉

    Auf jeden Fall hier jetzt ein lauffähiges Beispiel.
    Das Problem tritt übrigens auch hier auf, die erzeugte Datei ist aber UTF8, habs gecheckt.

    main.cpp:

    #include "widget.h"
    #include "dataio.h"
    #include <QApplication>
    
    int main(int argc, char *argv[])
    {
        DataIO* dataIO = new DataIO();
        dataIO->writeFile();
    
        QApplication a(argc, argv);
        Widget w(dataIO);
    
        w.show();
    
        return a.exec();
    }
    

    DataIO.h:

    #ifndef DATAIO_H
    #define DATAIO_H
    
    #include <fstream>
    #include <string>
    
    class DataIO
    {
    public:
        DataIO();
    
        std::string readFile();
        void writeFile();
    };
    
    #endif // DATAIO_H
    

    DataIO.cpp:

    #include "dataio.h"
    
    DataIO::DataIO(){}
    
    std::string DataIO::readFile(){
        std::string filePath = "testFile.txt";
        std::string FileData;
    
        std::ifstream is(filePath.c_str());
    
        FileData.assign( (std::istreambuf_iterator<char>(is) ),
                         (std::istreambuf_iterator<char>()   ) );
    
        return FileData;
    }
    
    void DataIO::writeFile(){
        std::string filePath = "testFile.txt";
        std::string fileData = "Test für Umlaute wie Ä, Ü, Ö.";
    
        std::ofstream os(filePath.c_str());
        os << fileData;
        os.close();
    }
    

    widget.h:

    #ifndef WIDGET_H
    #define WIDGET_H
    
    #include <QWidget>
    #include <QGridLayout>
    #include <QLabel>
    #include "dataio.h"
    
    class Widget : public QWidget
    {
        Q_OBJECT
    
    public:
        Widget(DataIO *dataIO, QWidget *parent = 0);
        ~Widget();
    
    private:
        QGridLayout* MainLayout;
    };
    
    #endif // WIDGET_H
    

    und zu guter letzt noch widget.cpp:

    #include "widget.h"
    
    Widget::Widget(DataIO* dataIO, QWidget *parent)
        : QWidget(parent)
    {
        MainLayout = new QGridLayout;
        QLabel* TestLabel = new QLabel(QString::fromStdString(dataIO->readFile()));
    
        MainLayout->addWidget(TestLabel);
    
        setLayout(MainLayout);
    }
    
    Widget::~Widget(){}
    

    Auf die Boost-Librarys habe ich hier verzichtet.

    VG
    Cherup



  • Sicher das es utf8 ist? -> Die umlaute sind als 2 bytes in der datei abgelegt.
    Mit was entwickelst du?
    Wenn es unter windows mit visual studio ist dann sind die umlaute in der text datei nicht als utf-8 kodiert gespeichert.
    Da Visual Studio für source code dateien keine utf-8 kodierung verwendet sondern eine ANSI kodierung.

    Versuch mal statt

    std::string fileData = "Test für Umlaute wie Ä, Ü, Ö.";
    

    das hier

    // UTF-8 codes for the umlauts be used inside string constants as octal escape sequence (otherwise we would create numbers which are bigger then a char can hold) and in "()" the pure utf8 codepoints
    			// ä: \303\244 (C3 A4)
    			// ö: \303\266 (C3 B6)
    			// ü: \303\274 (C3 BC)
    			// Ä: \303\204 (C3 84)
    			// Ö: \303\226 (C3 96)
    			// Ü: \303\234 (C3 9C)
    			// ß: \303\237 (C3 9F)
    std::string fileData = "Test für Umlaute wie \303\204, \303\234, \303\226.";
    

Log in to reply