Stahli: [C++] Unicode in Ascii umwandeln

Hallo,
ich arbeite zur Zeit an einem Programm, das bestimmte Inhalte bestimmter URLs abrufen, speichern, und dann bei Gelegenheit wieder ausgeben soll. Die HTML-Tags sind hier irrelevant, werden also rausgefiltert. Am liebsten würde ich diese Inhalte in einer CSV-Datei mit Ascii-Codierung ablegen, jedoch stehen mir noch die HTML-Entities im Wege...
In meiner Datei sollen natürlich keine Entities mehr vorhanden sein. Die sog. "named entities" muss ich mittels einer Liste ersetzen, bei den in der numerischen Notation vorliegenden Entities sollte dies auch ohne einer Liste möglich sein, denk ich. Wie kann ich also die gegebene Unicode-Nummer in die entsprechende Ascii-Nummer umwandeln (soweit wie eben möglich)? Mein Ansatz, das entsprechende Zeichen als wchar_t abzuspeichern und dann auf die Typumwandlung zu char zu hoffen, endete leider in leicht kryptografisch angehauchten Sonderzeichen.

Viele Grüße,
Felix

--
Nichts auf der Welt ist so gerecht verteilt wie der Verstand. Denn jedermann ist überzeugt, dass er genug davon habe.
René Descartes
  1. Wie kann ich also die gegebene Unicode-Nummer in die entsprechende Ascii-Nummer umwandeln (soweit wie eben möglich)?

    Die Nummerierung gleicher Zeichen in US-ASCII und Unicode ist identisch, ebenso jene in ISO-8859-1 und Unicode (siehe http://www.unicode.org/charts/, Basic Latin = US-ASCII, Latin 1 = ISO-8859-1[128 bis 255]). Du brauchst daher lediglich die Unicode-Nummer hernehmen, prüfen, ob sie kleiner als 128 bzw. 256 ist; falls ja, kannst du sie unverändert übernehmen, falls nein, wird ein Zeichen referenziert, dass in US-ASCII bzw. ISO-8859-1 nicht vorhanden ist und einen entsprechenden Platzhalter bekommen muss.

    Es wäre ratsam, statt des doch extrem eingeschränkten ASCII-Zeichensatzes, der nichtmal Umlaute enthält, geschweige denn das Eurosymbol (welches auch in iso-8859-1 nicht vorhanden ist), auch für die CSV-Datei Unicode zu nutzen, namentlich utf-8. utf-8 ist weitesgehend stolperfrei auch von Uraltprogrammen zu verarbeiten, transportiert aber gleichzeitig den gesamten Unicode-Bereich.
    Die Umwandlung einer wchar_t-Zeichenkette in eine utf-8-kodierte Zeichenkette lässt sich sehr leicht mit iconv erledigen (nur ein Funktionsaufruf). Beachte, dass zwar die Zeichen 128 bis 255 identisch sind (siehe oben), aber wegen der Kodierung die Bytewerte bei utf-8 nicht 1:1 übernommen werden können.

    1. Hallo,
      ich hatte ein Problem mit den Begriffen. Ich dachte Ascii würde ISO-8859-1 mit einschließen. Umlaute wären ganz nett :)

      Die Nummerierung gleicher Zeichen in US-ASCII und Unicode ist identisch, ebenso jene in ISO-8859-1 und Unicode

      Das dachte ich auch, bis ich bei einigen geladenen utf-8 codierten Quelltexten auf Probleme mit Umlauten stieß. Den Seitenquelltext lege ich in einem AnsiString-Objekt ab (also ISO-8859-1), trotzdem wird z.B. ä zu ä, ü zu ü, ö zu ö und ß zu ß. Woran kann das liegen?

      Es wäre ratsam, statt des doch extrem eingeschränkten ASCII-Zeichensatzes, der nichtmal Umlaute enthält, geschweige denn das Eurosymbol (welches auch in iso-8859-1 nicht vorhanden ist), auch für die CSV-Datei Unicode zu nutzen, namentlich utf-8.

      In diese Richtung gingen meine ersten Versuche, leider fand ich 1.) keine geeigneten Klassen oder Methoden, mit C++ utf-8 codierte Dateien zu erstellen, und 2.) bietet der verwendete (und mit zunehmender Einsicht ungenügende) Borland C++ Builder 4 keine grafischen Komponenten an, die utf-8 darstellen könnten. Entsprechende Packages von Drittanbieter waren leider immer mit der 4er-Version inkompatibel. Trotzdem wäre die Umstellung auf utf-8 das Optimalste.

      Viele Grüße,
      Felix

      --
      Nichts auf der Welt ist so gerecht verteilt wie der Verstand. Denn jedermann ist überzeugt, dass er genug davon habe.
      René Descartes
      1. Hi,

        ich hatte ein Problem mit den Begriffen. Ich dachte Ascii würde ISO-8859-1 mit einschließen.

        willkommen im Club! ;-)
        Darüber, was ASCII wirklich bedeutet, gibt es unglaublich viele falsche Überzeugungen. Manche glauben, ASCII sei die Hexdump-Darstellung eines beliebigen Dateiinhalts; manche glauben, ASCII sei einfach die numerische Darstellung von Zeichencodes.

        Die Nummerierung gleicher Zeichen in US-ASCII und Unicode ist identisch, ebenso jene in ISO-8859-1 und Unicode
        Das dachte ich auch, bis ich bei einigen geladenen utf-8 codierten Quelltexten auf Probleme mit Umlauten stieß. Den Seitenquelltext lege ich in einem AnsiString-Objekt ab (also ISO-8859-1), trotzdem wird z.B. ä zu ä, ü zu ü, ö zu ö und ß zu ß. Woran kann das liegen?

        Die Codenummern der Zeichen sind wohl identisch, nur werden Codes >0x7F in ISO-8859-1 (manchmal auch "ANSI" oder "extended ASCII" genannt) mit einem Byte codiert, in UTF-8 dagegen mit zwei oder mehr.

        In diese Richtung gingen meine ersten Versuche, leider fand ich 1.) keine geeigneten Klassen oder Methoden, mit C++ utf-8 codierte Dateien zu erstellen, und 2.) bietet der verwendete (und mit zunehmender Einsicht ungenügende) Borland C++ Builder 4 keine grafischen Komponenten an, die utf-8 darstellen könnten.

        Ich wollte eben vorschlagen, stattdessen das Windows-API zu bemühen; aber leider ist das, was Windows unter "Unicode" versteht, meistens UTF-16.

        Entsprechende Packages von Drittanbieter waren leider immer mit der 4er-Version inkompatibel.

        Mir ist nicht klar, was das mit der Compiler-Version zu tun haben sollte.

        Trotzdem wäre die Umstellung auf utf-8 das Optimalste.

        Hat "optimal" nicht bereits den Charakter eines Superlativs? ;-)

        So long,
         Martin

        --
        Denken ist wohl die schwerste Arbeit, die es gibt. Deshalb beschäftigen sich auch nur wenige damit.
          (Henry Ford, amerikanischer Industriepionier)
        1. Hallo,

          Darüber, was ASCII wirklich bedeutet, gibt es unglaublich viele falsche Überzeugungen.

          Da bin ich ja beruhigt.

          Die Codenummern der Zeichen sind wohl identisch, nur werden Codes >0x7F in ISO-8859-1 (manchmal auch "ANSI" oder "extended ASCII" genannt) mit einem Byte codiert, in UTF-8 dagegen mit zwei oder mehr.

          Aber wie kommt es dann zu diesen Zeichen? Auch, wenn sie mit zwei oder mehr Bytes codiert sind, müssten doch alle Bytes bis auf den letzten den Wert NUL haben, oder? Der letzte Byte beinhaltet dann die korrekte Nummer. Hab ich einen Denkfehler?

          Entsprechende Packages von Drittanbieter waren leider immer mit der 4er-Version inkompatibel.
          Mir ist nicht klar, was das mit der Compiler-Version zu tun haben sollte.

          Ein Beispiel. Es unterscheidet sich ja nicht nur der Compiler.

          Hat "optimal" nicht bereits den Charakter eines Superlativs? ;-)

          Hm, klingt logisch. Leider bin ich da nicht der einzige. :)

          Felix

          --
          Nichts auf der Welt ist so gerecht verteilt wie der Verstand. Denn jedermann ist überzeugt, dass er genug davon habe.
          René Descartes
          1. Hallo Felix,

            Die Codenummern der Zeichen sind wohl identisch, nur werden Codes >0x7F in ISO-8859-1 (manchmal auch "ANSI" oder "extended ASCII" genannt) mit einem Byte codiert, in UTF-8 dagegen mit zwei oder mehr.
            Aber wie kommt es dann zu diesen Zeichen? Auch, wenn sie mit zwei oder mehr Bytes codiert sind, müssten doch alle Bytes bis auf den letzten den Wert NUL haben, oder? Der letzte Byte beinhaltet dann die korrekte Nummer.

            Nein, so einfach ist es nicht. KANN es nicht sein, wenn man genauer darüber nachdenkt. Es scheitert daran, dass der Code 0x00 ("Null") in vielen Kontexten bereits eine eigene Bedeutung hat (markiert in C beispielsweise das Ende eines Strings).

            Hab ich einen Denkfehler?

            Ja.

            Entsprechende Packages von Drittanbieter waren leider immer mit der 4er-Version inkompatibel.
            Mir ist nicht klar, was das mit der Compiler-Version zu tun haben sollte.
            Ein Beispiel. Es unterscheidet sich ja nicht nur der Compiler.

            Mir ist nicht ganz klar, was man bei dem von dir verlinkten Angebot wirklich kauft. Das sind doch ganz gewöhnliche C++-Klassenbibliotheken, die sich mit jedem x-beliebigen C++-Compiler übersetzen lassen, oder nicht?
            Wenn nein, was ist es dann? Wo liegt das Problem?

            Hat "optimal" nicht bereits den Charakter eines Superlativs? ;-)
            Hm, klingt logisch. Leider bin ich da nicht der einzige. :)

            Ich weiß - oder meintest du "der einzigste"? Wie schon gesagt: Willkommen im Club. :-D

            Schönen Abend noch,
             Martin

            --
            Zwischen Leber und Milz
            passt immer noch'n Pils.
      2. Die Nummerierung gleicher Zeichen in US-ASCII und Unicode ist identisch, ebenso jene in ISO-8859-1 und Unicode
        Das dachte ich auch, bis ich bei einigen geladenen utf-8 codierten Quelltexten auf Probleme mit Umlauten stieß. Den Seitenquelltext lege ich in einem AnsiString-Objekt ab (also ISO-8859-1), trotzdem wird z.B. ä zu ä, ü zu ü, ö zu ö und ß zu ß. Woran kann das liegen?

        Martin hat das schon angesprochen: Der Witz (bzw. einer von zweien) an utf-8 ist, dass nirgends in einer utf-8-kodierten Kette ein Null-Byte erscheint, wo keines hingehört. Dieses Null-Byte würde als Zeichenkettenendeanzeiger alte Programme, die utf-8 noch nicht kennen, völlig aus dem Tritt bringen. Stattdessen werden bei Zeichenwerten, die mehr als 7 Bit benötigen, die Bits auf mehrere Bytes aufgeteilt, sozusagen ein paar ins erste Körbchen, ein paar ins zweite Körbchen und wenn's noch mehr sind, legen wir noch ein paar ins dritte Körbchen. An die Körbchen wird dann noch eine große 1 gemalt (achtes Bit wird gesetzt), damit man beim Auslesen auch erkennt, dass diese Körbchen bzw. ihr Inhalt zusammengehören.

        utf-8 ist also so ausgelegt, dass jedes Programm, das herkömmliche 8-bittige Zeichenketten verarbeiten kann, unfallfrei und ohne Änderungen auch mit utf-8-Ketten zurecht kommt. Es kommt wegen der Bitverteilung zwar zu Darstellungsfehlern in der Art, wie du sie oben beschrieben hast, aber es geht wenigstens nichts verloren.

        Wegen dieser speziellen Kodierung kannst Du zwar die nummerischen HTML-Masken 1:1 in eine iso-8859-1-Zeichenkette übernehmen (so Wert kleiner als 256), aber nicht 1:1 in eine utf-8-Zeichenkette.
        Lege sie stattdessen 1:1 in einer wchar-Kette ab, du hättest dann sozusagen Unicode roh, utf-32 (ist wchar 32 Bit breit?). Diese kannst du dann vom ganz breiten Unicode ins abgesicherte und kompaktere utf-8-Unicode konvertieren.

        Es wäre ratsam, […] Unicode zu nutzen

        In diese Richtung gingen meine ersten Versuche, leider fand ich 1.) keine geeigneten Klassen oder Methoden, mit C++ utf-8 codierte Dateien zu erstellen, und 2.) bietet der verwendete (und mit zunehmender Einsicht ungenügende) Borland C++ Builder 4 keine grafischen Komponenten an, die utf-8 darstellen könnten.

        Die Antwort mag blöd klingen, nimms mir nicht übel, aber dann programmiere halt mal ein wenig. Besagte iconv-Bibliothek erledigt die Konvertierung wie schon geschrieben mit nur einem Funktionsaufruf und die weitere Behandlung von utf-8-Zeichenketten unterscheidet sich in fast nichts von der Behandlung herkömmlicher Zeichenketten. Dafür braucht es keine großartigen Klassen, geschweige denn Bauklötze für die IDE. Die iconv-Bibliothek läuft auch unter Windows, vermutlich ist sie sogar schon bei dir installiert. Die Dateien für Compiler und Linker müsstest du dir allerdings suchen, falls es sie nicht bei den Gnus gibt.

      3. Hello out there!

        trotzdem wird z.B. ä zu ä, ü zu ü, ö zu ö und ß zu ß. Woran kann das liegen?

        Daran.

        See ya up the road,
        Gunnar

        --
        „Wer Gründe anhört, kommt in Gefahr nachzugeben.“ (Goethe)