Gerd Gruber: Unicode nach UTF-8 konvertieren

Hallo Leute,

ich finde für folgendes Problem leider keine Lösung.
Ich habe eine Datei, die in Unicode (!nicht UTF-8!) kodiert ist.
Ich brauche aber diese Daten unbedingt in UTF-8 kodiert.
Dazu lese ich diese Datei mit Hilfe von Perl in eine Variable $data ein.

Ich habe folgendes versucht:
  open(OUTPUT, ">> atest.txt") || die "kann datei1  nicht öffnen $!";
  print OUTPUT $data;
  close(OUTPUT);
  my $neudata = =encode('UTF-8', $data);
  open(OUTPUT, ">> btest.txt") || die "kann datei2  nicht öffnen $!";
  print OUTPUT $neudata ;
  close(OUTPUT);
Nun habe ich mit einem Hex-Editor die beiden Dateien atest.txt und btest.txt verglichen und folgendes gesehen.
a) ASCII-Zeichen werden richtig konvertiert (was ja auch identisch ist)
b) auch der erweiterte Bereich z.B. Unicode DF wird richtig nach UTF-8 C39F konvertiert (dies ist das deutsche sz).
c) Aber andere Zeichen z.B. Unicode 2022 wird nicht korrekt nach UTF-8 konvertiert, was dort E280A2 lauten müsste. Es bleibt dort einfach 2022 stehen.

Kann mir hier jemand helfen, wie ich mein Problem in Perl lösen kann?

vielen Dank im voraus

Gerd

  1. natürlich ist gemeint:
    my $neudata = encode('UTF-8', $data);
    Sorry für den Schreibfehler.
    Hat jemand zufällig einen Lösungsvorschlag?

  2. Moin!

    Ich habe eine Datei, die in Unicode (!nicht UTF-8!) kodiert ist.

    Das gibts nicht. "Unicode" ist keine Kodierungsform. UTF-8 ist eine, außerdem gibt es UTF-16, UTF-32, UTF-7 und vermutlich noch etliche andere, die inder Praxis irrelevant sind.

    Was also genau meinst du?

    Nun habe ich mit einem Hex-Editor die beiden Dateien atest.txt und btest.txt verglichen und folgendes gesehen.
    a) ASCII-Zeichen werden richtig konvertiert (was ja auch identisch ist)
    b) auch der erweiterte Bereich z.B. Unicode DF wird richtig nach UTF-8 C39F konvertiert (dies ist das deutsche sz).
    c) Aber andere Zeichen z.B. Unicode 2022 wird nicht korrekt nach UTF-8 konvertiert, was dort E280A2 lauten müsste. Es bleibt dort einfach 2022 stehen.

    Offenbar codiert deine Funktion byteorientiert alles, was >0x7F ist, und beläßt alles, was <0x80 ist.

    Dabei ist das Encoding von UTF-8 ja nicht wirklich kompliziert, wenn man tatsächlich den Codepoint des Unicode-Zeichens hat.
    http://www.unicode.org/faq/utf_bom.html

    - Sven Rautenberg

    --
    My sssignature, my preciousssss!
    1. Schon klar. Siehe:
      http://de.wikipedia.org/wiki/UTF-8
      aus Wikipedia, der freien Enzyklopädie

      UTF-8 (Abk. für 8-bit Unicode Transformation Format) ist die verbreitetste Kodierung für Unicode-Zeichen; dabei wird jedem Unicode-Zeichen eine speziell kodierte Bytekette von variabler Länge zugeordnet. UTF-8 unterstützt bis zu 4 Byte, auf die sich wie bei allen UTF-Formaten alle 1.114.112 Unicode-Zeichen abbilden lassen.

      Ich meine die Ausgangsdatei, die ich habe enthält uncodierte reine Unicodezeichen, bestehend aus jeweils 4 Hex-Zahlen.

      Dass ich dies selber nachprogrammieren kann, weis ich auch. Ich dachte jetzt nur, dass perl oder auf CPAN irgendwo was zu finden wäre, dass genau dies Funktion schon enthält.
      Ich habe leider nichts gefunden.

      Dann wird mir wohl oder über nichts anders übrigbleiben als es selbst zu machen.

      1. Moin!

        Ich meine die Ausgangsdatei, die ich habe enthält uncodierte reine Unicodezeichen, bestehend aus jeweils 4 Hex-Zahlen.

        Was heißt hier "Hex-Zahlen"? Buchstaben und Zahlen des Bereichs [0-9A-F]?

        Oder tatsächlich Bytewerte? Das wäre dann UTF-32 (4 Byte je Zeichen, von denen die meisten Nullbytes sind).

        Dass ich dies selber nachprogrammieren kann, weis ich auch. Ich dachte jetzt nur, dass perl oder auf CPAN irgendwo was zu finden wäre, dass genau dies Funktion schon enthält.
        Ich habe leider nichts gefunden.

        Du suchst offenbar einen Konverter von UTF-32 nach UTF-8.

        - Sven Rautenberg

        --
        My sssignature, my preciousssss!
      2. Moin!

        Dass ich dies selber nachprogrammieren kann, weis ich auch. Ich dachte jetzt nur, dass perl oder auf CPAN irgendwo was zu finden wäre, dass genau dies Funktion schon enthält.
        Ich habe leider nichts gefunden.

        Encode bzw. Decode machen, was du willst. Jedenfalls basierend auf dem Link, den Klaus Mock dir gegeben hat.

        Zuerst Decode aus UTF-32 (wenn es denn dieses Format ist), dann Encode auf UTF-8. Perl 5.8 speichert die Zeichen intern sowieso als UTF-8, wenn es notwendig ist.

        Laut Doku kann man das De- und Encoding auch direkt an das Lesen und Schreiben der Datei dranhängen.

        Siehe http://perldoc.perl.org/Encode.html

        - Sven Rautenberg

        --
        My sssignature, my preciousssss!
        1. nein, nein, nein, vollkommenes Missverständnis.

          Die Zeichen in der Datei sind so wie unter:
          http://de.selfhtml.org/inter/unicode.htm ganz unten zu sehen.
          Ein Zeichen wird mit 4 Hexadezimal-Zahlen repräsentiert (zwei Byte breiten Zeichen). Ganz normales Unicode. Nicht UTF-16 oder UTF-32 kodiert oder was auch auch immer (vollkommen uncodierte Unicode mit 2 Byte breiten Zeichen).
          Und genau dieses möchte ich in UTF-8 überführen und da dachte ich dass perl bestimmt so eine Funktion aufweisen kann, die das macht.
          Aber dem schein leider wohl nicht so zu sein.

          1. Moin!

            nein, nein, nein, vollkommenes Missverständnis.

            Die Zeichen in der Datei sind so wie unter:
            http://de.selfhtml.org/inter/unicode.htm ganz unten zu sehen.
            Ein Zeichen wird mit 4 Hexadezimal-Zahlen repräsentiert (zwei Byte breiten Zeichen). Ganz normales Unicode. Nicht UTF-16 oder UTF-32 kodiert oder was auch auch immer (vollkommen uncodierte Unicode mit 2 Byte breiten Zeichen).

            Das Problem ist: Es gibt kein "vollkommen uncodiertes Unicode".

            Unicode mit 2 Byte breiten Zeichen ist eine der verschiedenen Erscheinungsformen von UTF-16. Weil: Es gibt mehr als 0xFFFF verschiedene Unicode-Zeichen, Unicode ist KEIN 16-Bit-Zeichensatz, er ist per Definition eigentlich unbegrenzt, derzeit sind im Bereich von 0x00000000 bis 0x0010FFFF Zeichen definiert.

            Und genau dieses möchte ich in UTF-8 überführen und da dachte ich dass perl bestimmt so eine Funktion aufweisen kann, die das macht.
            Aber dem schein leider wohl nicht so zu sein.

            Du mußt verstehen, welches Encoding deine Datei hat. Wenn da irgendeine Form von Unicode drinsteht, dann hat diese eine der konkreten Codierungsformen. Codierung meint dabei nicht, dass es irgendwie kryptisch komplex berechnet wurde, sondern einfach eine simple Zuordnung "Wenn das Unicode-Zeichen mit dem Codepoint hex 0x2022 gemeint ist, dann speichere die Bytes W, X, Y und Z" - je nachdem, welche Zuordnungsvorschrift (die UTF-32, UTF-16, UTF-8 etc. heißen) benutzt wird, sieht das Ergebnis entsprechend aus.

            Die Ziffern hinter UTF stehen übrigens für die Breite einer "Einheit". UTF-32 benutzt 32-Bit-Einheiten (4 Byte), UTF-16 benutzt 16-Bit-Einheiten (2 Byte) und UTF-8 benutzt 8-Bit-Einheiten (1 Byte). Um aber einen Unicode-Codepoint angeben zu können, sind bei UTF-32 immer nur eine Einheit, bei UTF-16 eine oder zwei Einheiten, und bei UTF-8 zwischen einer und sechs Einheiten notwendig.

            Wenn du also glaubst, "normales Unicode mit 2 Bytes je Zeichen" zu haben, dann hast du sehr wahrscheinlich UTF-16 (ob in Big Endian oder Little Endian, das sagt dir die BOM (Byte Order Mark)), und bislang hast du nie gemerkt, dass auch in UTF-16 Zeichen vorkommen können, die aus zwei 2-Byte-Einheiten bestehen können!

            - Sven Rautenberg

            --
            My sssignature, my preciousssss!
            1. Supervielen Dank für die ausführlichen Hinweise.

              Daraus ergibt sich jetzt tatsächlich das die Datei in UTF-16 (was ja den Codepoints der Unicode-Zeichen entspricht) vorliegt. Und da perl UCS2 kennt kann dies dann mit:

              $data=encode("utf-8", decode("ucs2", $data));

              umgewandelt werden. Und die neue Datei ist laut Hex-Editor vollkommend korrekt erzeugt.

              Nochmals vielen Dank.

  3. Hallo,

    Kann mir hier jemand helfen, wie ich mein Problem in Perl lösen kann?

    hast Du schon http://perldoc.perl.org/perluniintro.html gelesen?

    Grüße
      Klaus

  4. Hallo,

    Kann mir hier jemand helfen, wie ich mein Problem in Perl lösen kann?

    Da ist noch eine Sache. Perl 5.6 hat einige Fehler bezüglich Unicode-Behandlung. Ich habe damit wirklich keine guten Erfahrungen gemahct. Erst nach einem Umstieg auf Version 5.8 konnte ich meine Unicode-Probleme lösen.

    Grüße
      Klaus