Umlaute Windows + Oracle SQL

Alles rund um die Programmierung mit Qt
dazedly
Beiträge: 197
Registriert: 3. Oktober 2010 15:38
Kontaktdaten:

Umlaute Windows + Oracle SQL

Beitrag von dazedly »

Hallo Leute!

Folgendes Problem:

Ich versuche über die Commandline unter WIndows Sonderzeichen korrekt auszugeben, aber habe keine Ahnung, was für ein Codec benötigt wird. Das Seltsame ist, dass die Datensätze aus der Oracle 11g xe Datenbank korrekt auf der Konsole dargestellt werden, aber wenn ich sie in eine Datei schreibe, sind die Umlaute im Ar***. Aus ö mach er mir z.B. Anführungszeichen 'Bj"rn' .
Mir fehlr jegliches Hintergrundwissen zu diesem anscheinend sehr komplexen Thema.
Angeblich sollen die Daten aus der Datenbank in "Windows-1252" kodiert geliefert werden, aber das ist irgendwie auch nicht richtig.
hier der Sourcecode:

Code: Alles auswählen

#include <QCoreApplication>
#include <QSqlDatabase>
#include <QStringList>
#include <QDebug>
#include <QSqlQuery>
#include <QSqlError>
#include <QTextCodec>
#include <stdlib.h>
#include <QFile>
#include <iostream>

int main(int argc, char* argv[])
{
    std::cout << "aeiou áéíóúäü" << endl;
   // putenv("NLS_LANG=AMERICAN_AMERICA.AL32UTF8");
    QCoreApplication app(argc,argv);
    QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));

    qDebug() << "aeiou áéíóúäü";
    QTextCodec::setCodecForCStrings(QTextCodec::codecForLocale());
    qDebug() << "aeiou áéíóúäü";
    QTextCodec::setCodecForCStrings(QTextCodec::codecForName("Windows-1252"));
    qDebug() << "aeiou áéíóúäü";
    QTextCodec::setCodecForCStrings(QTextCodec::codecForName("Windows-1250"));
    qDebug() << "aeiou áéíóúäü";
    QTextCodec::setCodecForCStrings(QTextCodec::codecForName("Windows-1253"));
    qDebug() << "aeiou áéíóúäü";
    QTextCodec::setCodecForCStrings(QTextCodec::codecForName("Windows-1254"));
    qDebug() << "aeiou áéíóúäü";
    QTextCodec::setCodecForCStrings(QTextCodec::codecForName("Windows-1255"));
    qDebug() << "aeiou áéíóúäü";
    QTextCodec::setCodecForCStrings(QTextCodec::codecForName("Windows-1256"));
    qDebug() << "aeiou áéíóúäü";
    QTextCodec::setCodecForCStrings(QTextCodec::codecForName("Windows-1257"));
    qDebug() << "aeiou áéíóúäü";
    QTextCodec::setCodecForCStrings(QTextCodec::codecForName("Windows-1258"));
    qDebug() << "aeiou áéíóúäü";
    QTextCodec::setCodecForCStrings(QTextCodec::codecForName("ISO 8859-13"));
    qDebug() << "aeiou áéíóúäü";
    QTextCodec::setCodecForCStrings(QTextCodec::codecForName("ISO 8859-14"));
    qDebug() << "aeiou áéíóúäü";
    QTextCodec::setCodecForCStrings(QTextCodec::codecForName("ISO 8859-15"));
    qDebug() << "aeiou áéíóúäü";
    QTextCodec::setCodecForCStrings(QTextCodec::codecForName("ISO 8859-16"));
    qDebug() << "aeiou áéíóúäü";

    QSqlDatabase db = QSqlDatabase::addDatabase("QOCI");
    db.setHostName("127.0.0.1");
    db.setDatabaseName("db");
    db.setUserName("user");
    db.setPassword("1234");
    qDebug() << "db.open()" << db.open();

    QSqlQuery query;
    db.transaction();
    query.setForwardOnly(true);
    query.prepare("SELECT WHERE VORNAME LIKE 'Bj%'");
    db.commit();
    qDebug() << "query.exec()" <<  query.exec();

    QFile f("tata.sql");
    f.open(QIODevice::WriteOnly|QIODevice::Text);
    QTextStream s(&f);
    qDebug() <<  s.codec()->name();

    while(query.next())
    {
        QString insertString = QString(%1,%2,%3,%4,%5,%6,%7,%8,%9);")
                .arg(query.value(0).toString())
                .arg(query.value(1).toString())
                .arg(query.value(2).toString())
                .arg(query.value(3).toString())
                .arg(query.value(4).toString())
                .arg(query.value(5).toString())
                .arg(query.value(6).toString())
                .arg(query.value(7).toString())
                .arg(query.value(8).toString())
                ;
        s << insertString << endl;
        qDebug() << "write patient with id: " << query.value(0).toByteArray() << query.value(1).toByteArray();
    }
    f.close();

    return 0;
}

Code: Alles auswählen

aeiou ├í├®├¡├│├║├ñ├╝5D95D800aeiou ßÚݾ·õ³
aeiou ├í├®├¡├│├║├ñ├╝
aeiou ├í├®├¡├│├║├ñ├╝
aeiou A?A®A¡AlAsAñAL
aeiou G?G®G¡G│G?GñG?
aeiou ├í├®├¡├│├║├ñ├╝
aeiou ?í?®?¡?│?¸???╝
aeiou ???®?¡?│???ñ?╝
aeiou C?C®C¡C│CrCñC╝
aeiou AíA®A¡A│A║AñA╝
aeiou CöC®C¡C│CrCñC╝
aeiou ├?├®├¡├g├?├C├?
aeiou ├í├®├¡├│├║├Ç├î
aeiou AAA®A¡AlA?AÇAî
db.open() true
query.exec() true
"System"
write patient with id:  "61" "Björn"
write patient with id:  "4137" "Björn"
write patient with id:  "4954" "Björn"
write patient with id:  "5215" "Björn"
write patient with id:  "7344" "Björn"
write patient with id:  "10150" "Björn Stephan"
write patient with id:  "7674" "Björn"
write patient with id:  "10858" "Bjoern"
write patient with id:  "10558" "Björn"
write patient with id:  "14166" "Björn"
write patient with id:  "16173" "Bjanka"
write patient with id:  "16921" "Björn"
write patient with id:  "16320" "Björn"
write patient with id:  "16015" "Björn"
write patient with id:  "18306" "Bjoern"
write patient with id:  "19675" "Björn"
write patient with id:  "19124" "Björn-Wolfgang"
write patient with id:  "22155" "Björn"
write patient with id:  "22744" "Björn"
write patient with id:  "20982" "Bjoern"
write patient with id:  "23094" "Björn"
write patient with id:  "25271" "Björn"
write patient with id:  "24067" "Bjoern Soenke"
write patient with id:  "24303" "Björn"
write patient with id:  "24996" "Björn"
write patient with id:  "25623" "Bjoern"
write patient with id:  "27255" "Bjoern"
write patient with id:  "27082" "Björn"
write patient with id:  "29443" "Björn"
write patient with id:  "28804" "Björn"
write patient with id:  "29649" "Björn"
write patient with id:  "29694" "Björn"
Betõtigen Sie die <RETURN> Taste, um das Fenster zu schlie▀en... 
Ich hatte auch schon versucht den Textstream diverse Codecs einzuflößen mit "setCodec()".
Ich brauche dringend Hilfe, ich weiß echt nicht mehr weiter bei diesem Codecquatsch...

Nachtrag:
Auch im QtCreator werden die Björns falsch ausgegeben in der Konsole und zwar wieder Anführungszeichen, statt öhs.
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Re: Umlaute Windows + Oracle SQL

Beitrag von Christian81 »

Umlaute direkt im Quellcode sind (vor allem unter Windows) eine sehr schlechte Idee. Man weiß weder wie der Compiler die Quellcode-Dateien interpretiert noch welche locale bei der Ausführung aktiv ist. Deshalb sind die Tests m.E. falsch. Deshalb im Quellcode immer nur ascii benutzen und für deine Tests würde ich QChar(ushort) benutzen und dort direkt den Unicode-Code übergeben. Dann bist Du sicher, dass im QString das korrekte drin steht.
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
dazedly
Beiträge: 197
Registriert: 3. Oktober 2010 15:38
Kontaktdaten:

Re: Umlaute Windows + Oracle SQL

Beitrag von dazedly »

Ok, das kann ich schonmal nachvollziehen, aber wie soll ich mit den Daten von Oracle verfahren. Vor allem hab ich keinen Plan, wie ich sicherstellen kann, dass die Daten korrekt in das Textfile geschrieben werden. Selbst der SQLDeveloper jat das Selbe Umlautproblem, aber sqlplus in der Konsole nicht...
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Re: Umlaute Windows + Oracle SQL

Beitrag von Christian81 »

Bei Oracle gibts sicher Einstellungen für die Locale - notfalls mal im Oracle-Qt-Treiber nachschauen wie das dort gehandelt wird.
Für die Textdatei musst Du Dir überlegen welches Encoding diese haben soll und dann mittels QTextLocale oder, wenn es einfaches UTF-8 ist mittels QString::toUtf8() die Daten rausschreiben. Musst natürlich dann beim Laden im Texteditor auch die richtige Locale benutzen.
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
dazedly
Beiträge: 197
Registriert: 3. Oktober 2010 15:38
Kontaktdaten:

Re: Umlaute Windows + Oracle SQL

Beitrag von dazedly »

So ich habe es nicht geschafft die Sonderzeichen richtig zu schreiben... Ich habe das File in UTF-8 gespeichert usw. Das Seltsame ist, dass es auf der cmd mit qDebug() richtig ausgegeben wird. Diese benutzt Standardmäßig IBM 850. Wenn ich das für die Datei benutze, ist es auch Hund. Ich habe jetzt mal die C++ Klassen von Oracle ausprobiert, aber die liefen nicht richtig. Mit openodci konnte ich connecten und abfragen. Aber es ist genau das selbe Trauerspiel!

Ich hole mir die Daten mittels:

Code: Alles auswählen

OCI_GetString(rs,2)


das liefert mir einen const char* zurück.

Ich benutze folgendes für qDebug() und für die Datei:

Code: Alles auswählen

QString::fromUtf8(OCI_GetString(rs,2))
Das kommt auf der cmd:
"BjöÖrnß°áÁàÀ"
Und das steht in der Datei:
Bj”™rnáø µ…

Das deckt sich auf mit den Ergebnissen vom SqlDeveloper, der bekommt es genauso wenig hin. Richtig ist es _immer_ nur auf der cmd. Sei es mit meinem Programm, oder das von Oracle.
Ich werde langsam verrückt -.-

Ich hoffe jemand von euch hat noch eine Idee.
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Re: Umlaute Windows + Oracle SQL

Beitrag von Christian81 »

Code: Alles auswählen

” = 0x94
™ = 0x99
Das ist definitiv nicht UTF-8 was in der Datei steht sondern wohl der Extended-ASCII Zeichensatz für IBM850 (siehe http://de.wikipedia.org/wiki/Codepage_850 ). Wenn Du also deinen Editor einstellst dass er diesen Zeichensatz benutzen soll dann wird es auch richtig angezeigt.
Deinen QTextStream solltest Du schon sagen was für einen Codec er benutzen soll - sonst ist es System - also IBM850 - also genau das was in der Datei steht...

/edit Damit du siehst ob Qt-intern die Daten richtig im QString vorliegen würde ich den String einfach in einem Widget/Label anzeigen.
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
dazedly
Beiträge: 197
Registriert: 3. Oktober 2010 15:38
Kontaktdaten:

Re: Umlaute Windows + Oracle SQL

Beitrag von dazedly »

Codec hatte ich Natürlich gesetzt!

Die ganze Zeit:

Code: Alles auswählen

s.setCodec(QTextCodec::codecForName("IBM 850"));
// oder
s.setCodec(QTextCodec::codecForName("UTF-8"));
beides schon versucht.

Inhalt mit IBM 850 gespeichert: Bjƒ??ƒ?½rnÇ­Ç÷¶ÿ¶æƒ?ݶú
Screenshot hänge ich an.

Edit: Und ja! Ich habe die Datei mit dem richtigen Encoding geöffnet.

Edit 2: Eben noch einmal ohne Erfolg versucht:

Code: Alles auswählen


QTextCodec::codecForName("cp850")->toUnicode(OCI_GetString(rs,2))
Ergebnis im UTF8 gespeicherten File:
BjÔÇØÔäórn├í├©┬á┬ÁÔǪ┬À
Dateianhänge
björn.png
björn.png (13.07 KiB) 11616 mal betrachtet
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Re: Umlaute Windows + Oracle SQL

Beitrag von Christian81 »

Das was das QLabel anzeigt ist eindeutig UTF-8 - und Du konvertierst von IBM850 - das kann ja nicht gehen. qDebug() gibt es richtig aus da Du dort korrekter Weise QString::fromUtf8(OCI_GetString(rs,2)) benutzt...
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
dazedly
Beiträge: 197
Registriert: 3. Oktober 2010 15:38
Kontaktdaten:

Re: Umlaute Windows + Oracle SQL

Beitrag von dazedly »

Ich hab bei dem Labeltext jetzt auch mal ein "QString::fromUtf8(OCI_GetString(rs,2))" gemacht und das sieht jetzt so aus:
Dateianhänge
björn2.png
björn2.png (6.86 KiB) 11607 mal betrachtet
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Re: Umlaute Windows + Oracle SQL

Beitrag von Christian81 »

Bitte gib mal die Hex-Codes von const char *OCI_String aus.

Code: Alles auswählen

const char *tmp = OCI_GetString(...)
int i = 0;
while(tmp[i] != 0) {
  unsigned int t = tmp[i];
  fprintf(stdout, "0x%02x", t);
  ++i;
}
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
dazedly
Beiträge: 197
Registriert: 3. Oktober 2010 15:38
Kontaktdaten:

Re: Umlaute Windows + Oracle SQL

Beitrag von dazedly »

0x420x6a0xffffffe20xffffff800xffffff9d0xffffffe20xffffff840xffffffa20x720x6e0xffffffc30xffffffa10xffffffc30xffffffb80xffffffc20xffffffa00xffffffc20xffffffb50xffffffe20xffffff800xffffffa60xffffffc20xffffffb7
BjöÖrnß°áÁàÀ
bzw
BjÔÇØÔäórn├í├©┬á┬ÁÔǪ┬À
odt
Beiträge: 128
Registriert: 12. August 2010 11:49
Kontaktdaten:

Re: Umlaute Windows + Oracle SQL

Beitrag von odt »

Ich griff in einem Projekt über den Qt-Treiber auf ne Ora zu und hatte, insofern mein Gedächtnis mich nicht täuscht, keine Zeichensatz-Probleme.

OCI übernimmt normalerweise die Zeichenkonvertierung. siehe Seite 20. Wie das Character-Set gewählt wird steht hier. Auf http://docs.oracle.com/cd/B10500_01/ser ... 29/ch6.htm findest Du etwa in der Mitte ein Beispiel.

Liefert OCI nicht Unicode? -> Versuch mal eine andere QString::from (Utf16? WCharArray?)
ODT Informatik GmbH, Reto Tschofenig
dazedly
Beiträge: 197
Registriert: 3. Oktober 2010 15:38
Kontaktdaten:

Re: Umlaute Windows + Oracle SQL

Beitrag von dazedly »

also die ocilib (opensource) unterstützt unicode, aber dafür finde ich keine Parameter. Auch bei dem Qt oci Treiber habe ich keine Option für das Encoding gefunden. Habe auch schon versucht die NLS_LANG zu setzen "_putenv("NLS_LANG=AMERICAN_AMERICA.AL32UTF8");" per c code wie auch per Hand.
An der Datenbank selbst kann/darf ich leider nichts umkonfigurieren. Mir ist eigentlich egal welcher codec benutzt wird, so lange ich es richtig auslesen kann. Verwirrend ist nur, dass die cmd als einzige in der Lage ist die Sonderzeichen richtig darzustellen.
Dateianhänge
björn3.png
björn3.png (59.13 KiB) 11582 mal betrachtet
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Re: Umlaute Windows + Oracle SQL

Beitrag von Christian81 »

Sorry aber wie gibts du das auf ein QLabel aus? Wenn Du es so machst wie es dort steht (QString::toUtf8()) dann kann es nix werden und Du solltest dich mal dringend mit QString und den Encodings allgemein beschäftigen. QLabel::setText() benötigt einen normalen QString! Zeig uns mal bitte den kompletten Code...
Die Hex-Werte, die ausgegeben werden, sehen für mich so aus als wäre es definitiv ein Problem mit der Datenbank und nicht mit Qt:

Code: Alles auswählen

0x42 - B
0x6a - j

0xe2
0x80
0x9d
 ---> utf-8 code für '"'
0xe2
0x84
0xa2
 ---> utf-8 code für 'tm' - Zeichen
0x72 - r
0x6e - n
Unter Umständen wurden die Daten auch nicht korrekt in die DB geschrieben oder der Datentyp der Spalte passt nicht. Aber an Qt liegt das hier definitiv nicht
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
dazedly
Beiträge: 197
Registriert: 3. Oktober 2010 15:38
Kontaktdaten:

Re: Umlaute Windows + Oracle SQL

Beitrag von dazedly »

Es kann durchaus sein, dass die Daten in der Datenbank nicht ganz korrekt sind, aber das liegt leider nicht in meiner Hand. Ich möchte nur das Ergebnis reproduzieren, welches mir qDebug() liefert. Es scheint die Sache ja richtig auszugeben.
Unten findest du wie gewünscht meinen Code.

Code: Alles auswählen

#include <iostream>
#include <ocilib.h>
#include <QApplication>
#include <QFile>
#include <QTextStream>
#include <QDebug>
#include <QTextCodec>
#include <fstream>
#include <QLabel>

#define OCI_CHARSET_UFT8

int main(int argc, char* argv[])
{
    qDebug() << "putenv" << _putenv("NLS_LANG=AMERICAN_AMERICA.AL32UTF8");
    QApplication app(argc,argv,true);

    OCI_Connection* cn;
    OCI_Statement* st;
    OCI_Resultset* rs;

    OCI_Initialize(NULL, NULL, OCI_ENV_DEFAULT);
    std::cout << "connect!" << std::endl;
    cn = OCI_ConnectionCreate("db", "user", "pw", OCI_SESSION_DEFAULT);
    st = OCI_StatementCreate(cn);

    std::cout << "connected!" << std::endl;
    printf("Server major    version : %i\n",   OCI_GetServerMajorVersion(cn));
    printf("Server minor    version : %i\n",   OCI_GetServerMinorVersion(cn));
    printf("Server revision version : %i\n\n", OCI_GetServerRevisionVersion(cn));
    printf("Connection      version : %i\n\n", OCI_GetVersionConnection(cn));

    OCI_ExecuteStmt(st, "select id, VORNAME FROM TABELLE WHERE VORNAME LIKE 'Bj%'");

    rs = OCI_GetResultset(st);


    QFile f("file1.txt");
    f.open(QIODevice::WriteOnly|QIODevice::Text);
    QTextStream s(&f);
    qDebug() <<  s.codec()->name();
    std::cout << "start!" << QString(s.codec()->name()).toStdString() << std::endl;
    s.setCodec(QTextCodec::codecForName("UTF8"));

    // ofstream File zum Vergleich
    std::ofstream myfile;
    myfile.open ("file2.txt");

    QLabel * lab = new QLabel();
    lab->show();
    QLabel * lab2 = new QLabel();
    lab2->show();
    QLabel * lab3 = new QLabel();
    lab3->show();
    QLabel * lab4 = new QLabel();
    lab4->show();
    QLabel * lab5 = new QLabel();
    lab5->show();


    bool first = false;
    while(OCI_FetchNext(rs))
    {
        if(!first)
        {
            lab->setText(QString::fromUtf8(OCI_GetString(rs,2)).append("  LABEL1 from utf8"));
            lab2->setText(QString(OCI_GetString(rs,2)).append("  LABEL2 plain"));
            lab3->setText( QTextCodec::codecForName("cp850")->toUnicode(OCI_GetString(rs,2)).append("  LABEL3 toutf8 from ibm 850"));
            lab4->setText( QTextCodec::codecForName("Windows-1252")->toUnicode(OCI_GetString(rs,2)).append("  LABEL4 toutf8 from windows 1252"));
            lab5->setText( QTextCodec::codecForName("UTF16")->toUnicode(OCI_GetString(rs,2)).append("  LABEL5 toutf8 from utf-16"));
        }
        first = true;

        s << QString::fromUtf8(OCI_GetString(rs,2)) << "\n";
        qDebug() << "id: " << OCI_GetInt(rs, 1) << QString::fromUtf8(OCI_GetString(rs,2));

        myfile << OCI_GetString(rs,2) << "\n";

    }

    myfile.close();
    f.close();

    OCI_Cleanup();

    return app.exec();
}
Antworten