wstring vs string - kurze Nachfrage





  • Eisflamme schrieb:

    Bei mir geht's nicht um die Ausgabe, ich will nur parsen. Also sagst Du, dass QString::toStdString() falsch arbeitet oder wie? Aber ein einfacher char kann doch nach wie vor nur 255 Zeichen halten, das ist doch per se schon limitiert.

    vllt wäre es nicht schlecht wenn du verräts, was du eigentlich parsen willst bzw. in welcher kodierung?



  • Eisflamme schrieb:

    Meine Frage, ob "wstring" seine Existenzberechtigung hat, rührt nämlich daher, dass ich zwar theoretisch weiß, was dahintersteckt, aber im Gedächtnis habe, dass hier vielfach gesagt wurde, dass string eigentlich genau so funktionieren kann (ich weiß nicht mehr wie, vll einfach durch zwei char pro Zeichen im string) und wstring daher unnötig ist.

    Jein. Du kannst in einem std::string UTF8-kodierte Codepoints speichern und damit den gesamten Unicode-Raum abdecken. UTF8 hat viele nette Eigenschaften, die das ganze relativ straightforward machen, dennoch gibt es einige Dinge zu beachten.

    Ein Unicode-Codepoint in UTF-8-Kodierung kann dann mehrere Bytes (bis zu 4, theoretisch ginge auch noch mehr) in Anspruch nehmen. Gleichzeitg behalten die Codepoints unterhalb von 128 ihren von ASCII gewohnten Wert.

    Sachen, bei denen du dann natürlich aufpassen musst, ist z.B. das Splitten von UTF8-Strings. Du kannst nicht einfach an jedem beliebigen Index splitten. An einem bestimmten Codepoint splitten, ist aber immer noch trivial.

    IMHO ist UTF-8 immer noch die mit Abstand netteste Art und Weise mit kodiertem Unicode umzugehen. Die Links von theta sind schon mal ein guter Anfang. Weiter gehts hier (weiterführende Links beachten):
    http://research.swtch.com/utf8



  • Eisflamme schrieb:

    Werner: Wie würdest Du mein Problem dann wohl lösen?

    Hallo Eisflamme,

    Wenn Du dieses Problem meinst:

    Eisflamme schrieb:

    QString::toStdString() konvertiert mir die Eurozeichen zu '?'... wenn ich es zu wstring konvertiere, klappt's. Also hat wstring doch seine Existenzberechtigung?

    und Du den String nachher nur parsen möchtest, so würde ich QString::toStdWString() vorschlagen und anschließend parst Du den std::wstring . Die Zeichen sind dann halt vom Typ wchar_t und nicht char - ansonsten wie gehabt.
    Lt. Doku wird bei toStdString nach UTF-16 konvertiert, also musst Du theoretisch noch sicherstellen, dass bei keinem der Zeichen das Bit15 gesetzt ist. In der Praxis (nur europäische gängige Zeichen - z.B. '€') kannst Du Dir das wahrscheinlich sparen (s. mein Hinweis auf die Codes der chinesischen Zeichen oben). D.h. Du hast einen Text vor Dir, der eins zu eins in jedem Element genau ein Zeichen enthält.

    Wenn Du nur sehr wenige Zeichen hast, die >0x7f sind, könntest Du Dir auch eine eigenen CodePage definieren und diese Zeichen im Bereich von 0xA1 bis 0xFF unterbringen. Das müsste über QTextCodec::setCodecForLocale funktionieren. Anschließend kannst Du dann mit QString::toLocal8Bit ein QByteArray erzeugen, welches man dann in einen std::string konvertieren muss.

    Gruß
    Werner

    Nachtrag: ich sehe gerade, dass in CP858 das Euro-Zeichen (Code 0xD5) enthalten ist.



  • Hi,

    danke allerseits! Habe den ersten Artikel von theta komplett gelesen. wchar_t ist also UCS-2 = UTF-16. Da das eine Unicode-Art ist, kann man also durchaus sagen, dass C++ einen Teil des Unicodes unterstützt. Bietet irgendeine Bibliothek (boost oder so) denn eine UTF-8-Stringklasse an, auf die man mit [] korrekt zugreifen kann?

    pars0r:
    Eigentlich ist das fast alles nur im Bereich von Bit 0-127. Einzig dazu kommen die Währungszeichen Pfund und Euro.

    Insofern wäre eine eigene Codepage vielleicht gar nicht schlecht. Aber wstring erscheint mir gerade einfacher. Was spricht denn dagegen?



  • Ist richtig. Wo fange ich da am besten an? Gibt es da eine gute Seite, die auch die C++-Implementierung diskutiert?

    http://en.wikipedia.org/wiki/Code_page
    http://en.wikipedia.org/wiki/Utf8
    http://en.wikipedia.org/wiki/UTF-16
    http://en.wikipedia.org/wiki/Unicode
    http://msdn.microsoft.com/en-us/library/windows/desktop/dd317711%28v=vs.85%29.aspx
    http://msdn.microsoft.com/en-us/library/windows/desktop/dd317752%28v=vs.85%29.aspx

    Meine Frage, ob "wstring" seine Existenzberechtigung hat, rührt nämlich daher, dass ich zwar theoretisch weiß, was dahintersteckt, aber im Gedächtnis habe, dass hier vielfach gesagt wurde, dass string eigentlich genau so funktionieren kann (ich weiß nicht mehr wie, vll einfach durch zwei char pro Zeichen im string) und wstring daher unnötig ist.

    Wenn man es streng nimmt, ist dies Blödsinn. Schreibe mal in deinem String: "Schräglage: β = 1.5"

    Natürlich kann man std::string als einen String in einer speziellen Kodierung auffassen. Aber damit unterläuft man die eigentliche Bedeutung von std:string bzw. std::basic_string<char>.



  • Werner Salomon schrieb:

    Lt. Doku wird bei toStdString nach UTF-16 konvertiert

    Du meinst hier sicher toStdWString. Das gilt dann auch nur wenn wchar_t 2 Byte hat. Falls wchar_t 4 Byte hat wird ucs4 verwendet.





  • Eisflamme schrieb:

    pars0r:
    Eigentlich ist das fast alles nur im Bereich von Bit 0-127. Einzig dazu kommen die Währungszeichen Pfund und Euro.

    Insofern wäre eine eigene Codepage vielleicht gar nicht schlecht. Aber wstring erscheint mir gerade einfacher. Was spricht denn dagegen?

    du willst also jedem einzelnen zeichen, das von haus aus in ein byte passt, einen (mindestens) doppelt so großen (wenn nicht gar vierfachen) speicherplatz verschaffen, damit es ihm nicht so eng wird?
    🤡
    mal im ernst, was hättest du davon und was wäre dann einfacher?

    du willst parsen, aber nicht darstellen, richtig?
    wenn du darstellen müsstest, dann müsstest du je nach system die codepage(windows)/kodierung sowieso beachten. unter linux dagegen könntest du alles utf-8 kodiert mit cout raushauen, aber auch unter linux lässt sich die codepage setzen.



  • Ich moecht mich hier gleich mal anschießen und fragen wie man richtig von (windows) wchar_t zu utf-8 konvertiert.

    Ich bin mal ueber diesen Codeschnipsel gestolpert:

    namespace utf8 {
    
    std::string to(const std::wstring& data) {
    	std::wstring_convert<std::codecvt_utf8_utf16<wchar_t> > c;
    	return c.to_bytes( data );
    }
    std::wstring from(const std::string& data) {
    	std::wstring_convert<std::codecvt_utf8_utf16<wchar_t> > c;
    	return c.from_bytes( data);
    }
    
    }
    

    Ist das richtig soweit oder sollte man da was anderes benutzten?
    Gruessle



  • pars0r:
    Speicherplatz ist egal, die zu parsenden Teile sind nicht groß.

    Was ich davon hätte? Ich kann das Ding wie einen ganz normalen string nutzen. Bisher habe ich keinen Vorschlag gesehen, der einfacher wäre.



  • alles im qstring lassen?
    😕



  • Der Parser liegt im Backend, QT ist bei mir ausschließlich Frontend. Das Backend soll auch ohne QT funktionieren.



  • Eisflamme schrieb:

    Was ich davon hätte? Ich kann das Ding wie einen ganz normalen string nutzen. Bisher habe ich keinen Vorschlag gesehen, der einfacher wäre.

    std::basic_string<wchar32_t> bzw. std::u32string ?



  • ...

    Und was ist daran einfacher?



  • Eisflamme schrieb:

    Und was ist daran einfacher? -.-

    Es ist genauso einfach, aber dafür korrekt.



  • stuxn schrieb:

    Ich moecht mich hier gleich mal anschießen und fragen wie man richtig von (windows) wchar_t zu utf-8 konvertiert.

    Unter Windows kann man (auch) die WinAPI dafür nehmen:

    #include <windows.h>
    #include <iostream>
    #include <string>
    
    using namespace std;
    
    wstring toWide(string in, UINT from)
    {
       int len = MultiByteToWideChar(from, 0, in.c_str(), -1, 0, 0);
    
       if(!len)
          cout << "Fehler toWide?!\n";
    
       WCHAR *res = new WCHAR[len];
    
       int result = MultiByteToWideChar(from, 0, in.c_str(), -1, res, len);
    
       if(result != len)
          cout << "Fehler toWide?!\n";
    
       wstring s(res);
    
       delete[] res;
    
       return s;
    }
    
    string toMultiByte(wstring in, UINT to)
    {
       const int len = WideCharToMultiByte(to, 0, in.c_str(), -1, 0, 0, 0, 0);
    
       if(!len)
          cout << "Fehler toMBCS 1?!\n";
    
       char *res = new char[len];
    
       int result = WideCharToMultiByte(to, 0, in.c_str(), -1, res, len, 0, 0);
    
       if(result != len)
          cout << "Fehler toMBCS2?!\n";
    
       string s(res);
    
       delete[] res;
    
       return s;
    }
    
    string AnsiToUTF8(const string &in)
    {
       wstring tmp = toWide(in, CP_ACP);
       string res = toMultiByte(tmp, CP_UTF8);
       return res;
    }
    
    string UTF8ToAnsi(const string &in)
    {
       wstring tmp = toWide(in, CP_UTF8);
       string res = toMultiByte(tmp, CP_ACP);
       return res;
    }
    
    int main()
    {
       string utf8 = AnsiToUTF8("äöÜ");
       string ansi = UTF8ToAnsi(utf8);
    
       cout << utf8;
       cerr << ansi;
    
    }
    

    Dein Codeschnipsel sieht weitaus einfacher aus, aber ob er korrekt ist, weiß ich nicht.



  • Eisflamme schrieb:

    Lesen der Qt Dokumentation bedeutet auch, den "siehe auch" Links zu folgen!

    Genau, ich lese die gesamte QT Dokumentation durch und folge allen "siehe auch"-Links. Sorry, aber wenn Du weißt, was ich Deiner Meinung nach nachschlagen soll, dann sag es doch einfach statt einen minder sinnvollen Hinweis wie "Les die QT Dokumentation" zu geben... nett gemeint, danke, aber war für mich nicht hilfreich.

    War nur nicht hilfreich, weil du nicht fähig/willens(/...?) bist Dokumentation zu lesen.
    Ich meine hallo, wenn da steht "alles was QTextCodec::codecForCStrings() nicht konvertieren kann" (sinngemäss), dann ist logischerweise die nächste Frage "na was kann denn QTextCodec::codecForCStrings()?".
    Dann guckst du nach, siehst dass man da was umstellen kann und *schwupps* hättest du zum ersten mal nicht-trivialen Gebrauch einer Doku gemacht.

    Natürlich kannst du stattdessen auch alle Leute anpflaumen die dir nahelegen mal in der Doku nachzusehen. Dauert länger und du lernst nix dabei, aber naja ... ist deine Entscheidung.



  • hättest du zum ersten mal nicht-trivialen Gebrauch einer Doku gemacht.

    Na ja, wenn Du mir einfach Dinge unterstellst, kann ich Deine Kritik an meiner Kritik einer Antwort (was hier im Forum aber sowieso - sinnloserweise - kategorisch ein No-Go ist) nicht ernst nehmen, auch wenn da wahre Punkte dran sind.

    Zum Thema:
    Was ist an

    std::basic_string<wchar32_t> bzw. std::u32string

    korrekter? wstring ist meinem Verständnis nach die UTF-16-Enkodierung für Unicode, die valide und keineswegs inkorrekt ist. wchar32_t oder u32string zu verwenden nutzt immer noch nicht UTF-8 aus. Solange UTF-16 meine Sonderzeichen beinhaltet, erscheint mir das nach wie vor als einfachste (und gleichzeitig speicherschonenste) Variante meine Problemstellung zu lösen. Die optimale Lösung scheint es ja tatsächlich nicht zu geben.

    Auch ein Projekt, auf das in dem Artikel ( http://www.joelonsoftware.com/articles/Unicode.html ) verwiesen wird, fällt die Entscheidung auf UTF-16. Bestätigt doch, dass das valide ist, oder?



  • Eisflamme schrieb:

    wstring ist meinem Verständnis nach die UTF-16-Enkodierung für Unicode, ...

    Nein (s. mein erstes Posting in diesem Thread) - man kann wstring so 'missbrauchen', wenn man es darauf anlegt, aber so ist std::wstring nicht gemeint.

    .. vielleicht melde ich mich später noch mal.

    Gruß
    Werner


Anmelden zum Antworten