[gelöst] Umlaute in QString aus stdString



  • 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.";
    


  • Ich entwickel mit dem QtCreator unter Ubuntu 14.04.

    Ich bin sicher, dass es UTF-8 ist, der Linuxkonsolen-Befehl "file -bi" gibt mir als charset UTF8 an und im Hex-Editor werden die Umlaute mit 2 Bytes kodiert angezeigt.

    Dein Vorschlag funktioniert leider nicht, bleibt die gleiche Ausgabe. Ich habe die testFile.txt vor dem Durchlauf auch gelöscht, damit sie neu angelegt wird.

    Vielleicht ist es einfach ein "Ubuntu-Problem", die Group-Boxes werden auch nicht gezeichnet. (Das ist keine Frage nach Hilfe, gibt schon einen längeren Thread dazu 😉 )

    VG
    Cherup

    Edit:
    Ich hab nochmal versucht für FileData als Typ den std::wstring zu nutzen und die Rückgabe und die QLabel-Textzuweisung entsprechend auf wString umgestellt.
    Ebenfalls kein Erfolg. Es werden allerdings andere Zeichen angezeigt



  • hier wird aus einer kleinen Sache aber ein großer Schuh/Thread!

    Du ließt die Datei byteweise in einen std:string.
    std:string ist für "single-byte characters" ausgelegt!
    http://www.cplusplus.com/reference/string/string/

    Note that this class handles bytes independently of the encoding used: If used to handle sequences of multi-byte or variable-length characters (such as UTF-8), all members of this class (such as length or size), as well as its iterators, will still operate in terms of bytes (not actual encoded characters).

    std::wstring ist für 2-Byte-Zeichen ausgelegt. Wenn du also deine Datei in Unicode 16-Bit wandelst und std::wstring verwendest sollte es gehen.

    Ich kenne keine std-C-Funktion für codec-Wandlung, deshalb nutzt man unter Windows dafür auch die Windows-Funktion MultiByteToWideChar etc.
    Deshalb die Empfehlung komplett Qt zu verwenden.



  • Softwaremaker schrieb:

    hier wird aus einer kleinen Sache aber ein großer Schuh/Thread!

    Aber auch nur weil Cherup zuwenig informationen liefert.

    Softwaremaker schrieb:

    QString::fromStdString() nutzt intern QString::fromUtf8(const char * str, int size = -1)

    Stimmt aber nur für Qt5

    Laut der Dokumentation von Qt 4 verwendet QString::fromStdString intern QString::fromAscii

    http://doc.qt.io/qt-4.8/qstring.html#fromStdString

    http://doc.qt.io/qt-5/qstring.html#fromStdString

    Und da es bei Ihm mit QString::fromStdString nicht klappt vermute ich dass er Qt4 verwendet.

    Wenn ich QString::fromUtf8 verwendet passt es immer. (Egal ob Qt4 oder Qt5)

    QString::fromUtf8(FileData.data(), static_cast<int>(FileData.size()));
    


  • Morgen,

    warum liefere ich zu wenig Infos? Ich habe bereits im ersten Beitrag geschrieben, dass ich als OS Linux nutze, auf die Idee nachzuschauen, ob die Datei in UTF8 ist bin ich erst durch euch gekommen und die FileRead-Funktion habe ich auch recht früh gepostet.
    Zugegeben, die Qt-Version habe ich noch nicht geschrieben, die ist übrigens 5.2.
    Und ja ich hätte auch das Minimalbeispiel früher posten können.
    Ich werde versuchen, in Zukunft möglichst mehr Infos in den Startbeitrag zu packen.

    Ich möchte nach wie vor kein Qt in meiner Kern-Logik haben, die GUI soll als Modul bleiben. Ich werden mir mal in der Qt-Referenz QString::fromUTF8 anschauen um zu verstehen, was du mit deinem Codebeispiel meinst. Und mal sehen, was die Boost-Library für den Daten-IO hergibt.

    Cherup



  • ich würde dann als Puffer zum Einlesen der Daten aus der Datei keinen std:string verwenden. Besser den Speicher mit malloc usw. anlegen, darin die Datei einlesen und dann den Zeiger und Größe an QString mit fromUtf8 übergeben.
    Wenn die Daten von Qt wieder in die Datei sollen, dann mit QString::toUtf8 ein QByteArray erzeugen und dieses hat ::constData() und ::size() das an die Datei-Schreibfunktion übergeben wird.



  • Cherup schrieb:

    Zugegeben, die Qt-Version habe ich noch nicht geschrieben, die ist übrigens 5.2.

    Sicher das du Qt5 in deinem Programm verwendest? Qt Creator kennt verschiedene Kits, die wiederum beschreiben welche Qt Version und für welche Platform (z.b. Desktop, Android) das Programm übersetzt werden soll.

    Und mein code beispiel zeigt wie in Qt 5 QString::fromStdString intern QString::fromUtf8 aufruft. Nur auf den namen der std::string variable in einem lauffähigen Beispiel gemünzt



  • Softwaremaker schrieb:

    ich würde dann als Puffer zum Einlesen der Daten aus der Datei keinen std:string verwenden. Besser den Speicher mit malloc usw. anlegen, darin die Datei einlesen und dann den Zeiger und Größe an QString mit fromUtf8 übergeben.

    Wiso kein std::string verwenden und stattdessen manuelles speicher management betreiben?
    Wenn schon kein std::string dann eher ein std::vector<char>



  • firefly schrieb:

    Wiso kein std::string verwenden und stattdessen manuelles speicher management betreiben?
    Wenn schon kein std::string dann eher ein std::vector<char>

    Mache wenig mit std, deswegen konnte ich nur malloc nennen. Aber jedenfalls sollte er nicht std::string verwenden, das würde den Eindruck erwecken, das dort ein Ein-Byte-Encoded-Text enthalten ist, ist aber ein Utf-8, die std:string-Funktionen sind alle für Ein-Byte-Encoded-Text ausgelegt.
    Deine Empfehlung mit std::vector<char> passt.



  • Softwaremaker schrieb:

    firefly schrieb:

    Wiso kein std::string verwenden und stattdessen manuelles speicher management betreiben?
    Wenn schon kein std::string dann eher ein std::vector<char>

    Mache wenig mit std, deswegen konnte ich nur malloc nennen. Aber jedenfalls sollte er nicht std::string verwenden, das würde den Eindruck erwecken, das dort ein Ein-Byte-Encoded-Text enthalten ist, ist aber ein Utf-8, die std:string-Funktionen sind alle für Ein-Byte-Encoded-Text ausgelegt.
    Deine Empfehlung mit std::vector<char> passt.

    Okay das war jetzt genug Unfug. std::string ist DIE Wahl, wenn man mit UTF8 hantiert. Der Vollständigkeit halber: für UTF16 gibt’s std::u16string und für UTF32 gibt’s std::u32string . Fang bloß nicht an mit std::wstring herumzubasteln, das ist für nichts zu gebrauchen.
    So wie Cherup die Datei einliest ist schon in Ordnung, es muss also ein Qt Problem sein den String korrekt als UTF8 zu interpretieren. Da ich keine Ahnung von Qt habe, kann ich da nicht behilflich sein.


Anmelden zum Antworten