pl: Zeichenkodierung

0 72

Zeichenkodierung

pl
  • javascript
  1. 3

    Zeichenckodierung

    Christian Kruse
  2. 1
    Gunnar Bittersmann
    1. 0
      TS
      • codierung
      • javascript
      1. 1
        Gunnar Bittersmann
      2. 0
        dedlfix
      3. -2
        pl
        1. 1
          Rolf B
          1. 0
            Gunnar Bittersmann
            1. 0
              Rolf B
            2. 1
              usb
              1. 0
                Rolf B
                • codierung
                • javascript
                • unicode
                1. 0
                  usb
                  1. 0
                    Rolf B
          2. -1
            pl
            1. 0
              Rolf B
              1. 0
                pl
                1. 0
                  Patrick C.
                  1. 0
                    dedlfix
                    1. 0
                      Gunnar Bittersmann
                    2. 0
                      Rolf B
                  2. -4
                    pl
                    1. 0
                      Rolf B
                      1. -4
                        pl
                        1. 0
                          Gunnar Bittersmann
                          1. 0
                            pl
                            1. 0
                              Gunnar Bittersmann
                        2. 0
                          Rolf B
                          1. 0
                            pl
                            1. 0
                              Rolf B
                              1. 0
                                pl
                                1. 0
                                  Rolf B
                                  1. 0
                                    pl
                            2. 0
                              pl
                              1. 0
                                Rolf B
                                1. 0
                                  dedlfix
                                  1. 0
                                    Rolf B
                                    1. 1
                                      dedlfix
                                      1. 0
                                        Rolf B
                                    2. 0
                                      pl
                                      1. 1
                                        dedlfix
                                        1. 0
                                          pl
                                          1. 0
                                            dedlfix
                                          2. 0
                                            Rolf B
                                            1. 0
                                              pl
                                            2. 0
                                              pl
                                              1. 0
                                                Rolf B
                                                1. 0
                                                  pl
                                                  1. 0
                                                    TS
                                      2. 0
                                        usb
                                        1. 0
                                          pl
                                          1. 0
                                            usb
                                2. 0
                                  pl
                                3. 3
                                  1unitedpower
                                  1. 0
                                    Christian Kruse
                                  2. 0
                                    Rolf B
                      2. 0
                        pl
                        1. 0
                          Christian Kruse
                          1. 0
                            Gunnar Bittersmann
                            1. 0
                              Rolf B
                              1. 0
                                Auge
                                1. 0
                                  Gunnar Bittersmann
                        2. 1
                          dedlfix
                        3. 0
                          Rolf B
                          1. -1
                            pl
                            1. 0
                              Rolf B
                              1. 0
                                Gunnar Bittersmann
                                1. 0
                                  dedlfix
                                2. 0
                                  Rolf B
  3. 1
    MudGuard
  4. 2
    Rolf B
    1. 0
      pl

moin,

warum sehe ich hier kein Eurozeichen sondern 3 Andere?

console.log(String.fromCharCode(0xe2,0x82,0xac) );

Es sind doch die richtigen Zahlen. MfG

  1. Hallo pl,

    console.log(String.fromCharCode(0xe2,0x82,0xac) );
    

    Es sind doch die richtigen Zahlen.

    Nein. Der Codepoint für das Euro-Zeichen ist U+20AC. Richtig wäre also String.fromCharCode(0x20AC).

    LG,
    CK

  2. @@pl

    warum sehe ich hier kein Eurozeichen sondern 3 Andere?

    console.log(String.fromCharCode(0xe2,0x82,0xac) );
    

    Weil du immer noch nicht auf der Ebene angekommen bist, Zeichen als Zeichen zu behandeln und nicht als Bytes.

    LLAP 🖖

    --
    „Wer durch Wissen und Erfahrung der Klügere ist, der sollte nicht nachgeben. Und nicht aufgeben.“ —Kurt Weidemann
    1. Hello lieber Gunnar,

      warum sehe ich hier kein Eurozeichen sondern 3 Andere?

      console.log(String.fromCharCode(0xe2,0x82,0xac) );
      

      Weil du immer noch nicht auf der Ebene angekommen bist, Zeichen als Zeichen zu behandeln und nicht als Bytes.

      Definiere bitte "Zeichen" und "Symbol", bzw. "Glyphe". Sonst komme ich nämlich auch nicht mit.

      Soweit ich das bisher verstanden habe, wird das Eurosymbol hier mittels zweier Zeichen codiert, oder ist das falsch?

      Glück Auf
      Tom vom Berg

      --
      Es gibt nichts Gutes, außer man tut es!
      Das Leben selbst ist der Sinn.
      1. @@TS

        Definiere bitte "Zeichen" und "Symbol", bzw. "Glyphe". Sonst komme ich nämlich auch nicht mit.

        Soweit ich das bisher verstanden habe, wird das Eurosymbol hier mittels zweier Zeichen codiert, oder ist das falsch?

        Ja, ist es.

        Das Eurosymbol ist ein Symbol ist ein Zeichen. Dieses hat – wie CK schon sagte – den Zeichencode (codepoint) U+20AC.

        Dass dieser Codepoint in UTF-8 durch 3 Bytes codiert wird, interessiert an dieser Stelle außer Hotti vermutlich niemanden.

        Glyphen sind graphische Repräsentationen von Schriftzeichen. In einer Schriftart könnte die Glyphe fürs Eurosymbol so aussehen wie urspünglich gestaltet:

        Konstruktionszeichnung des Eurosymbols

        In einer anderen Schriftart könnte die Glyphe fürs Eurosymbols so aussehen wie ein großes C dieser Schriftart mit zwei Querstrichen.

        LLAP 🖖

        --
        „Wer durch Wissen und Erfahrung der Klügere ist, der sollte nicht nachgeben. Und nicht aufgeben.“ —Kurt Weidemann
      2. Tach!

        Weil du immer noch nicht auf der Ebene angekommen bist, Zeichen als Zeichen zu behandeln und nicht als Bytes.

        Definiere bitte "Zeichen" und "Symbol", bzw. "Glyphe". Sonst komme ich nämlich auch nicht mit.

        Javascript läuft (serverseitiges Javascript auslassend) im Browser als Aufsatz zu HTML. Es kommt theoretisch nicht mit physikalischen Gegebenheiten in Berührung. Das Dekodieren von Code und Texten hat bereits der Browser getan, bevor Javascript an die Reihe kommt. Somit liegen auf der Ebene, auf der Javascript arbeitet, keine "Zeichen, UTF-8-kodiert" mehr vor, sondern nur noch "Zeichen" so wie sie in Unicode definiert sind, unabhängig von UTFs.

        Auch Zahlen existieren in Javascript nur als das theoretische Gebilde und nicht in irgendwelchen physikalischen Speicherformen wie 8/16/32/64-Bit Integer oder Floats. Für Zahlen gibt es einfach nur den Typ Number.

        dedlfix.

      3. he Tom,

        Soweit ich das bisher verstanden habe, wird das Eurosymbol hier mittels zweier Zeichen codiert, oder ist das falsch?

        Wie kommst Du denn darauf? Zeichen werden immer mit Bytes kodiert und für das Eurozeichen sind es 3 Bytes mit den hier gezeigten Wertigkeiten.

        MfG

        1. Hallo pl,

          Nein, Nein, Nein.

          Zeichen werden durch Zahlen codiert. In Falle klassischer Zeichensätze im Bereich von 0 bis 255, was die Illusion erzeugte, Zeichen und Bytes seien das gleiche. Bei Unicode sind es Zahlen im Bereich von 0 bis 0x10ffff.

          Wenn es nötig ist, diese Zahlen irgendwo auf ein Speicher- oder Transportmedium zu bringen, werden sie mittels eines Encodings in eine Bytesequenz übersetzt. Z.B. UTF-8 oder UTF-16.

          Laufzeitumgebungen wie JavaScript oder .net nutzen UTF-16 auch für die Darstellung im Speicher. Das API versteckt das vor dir.

          Libraries wie StringView.js führen diese Übersetzung transparent aus und lassen dich einen UTF-8 codierten ArrayBuffer wie einen Unicode-String behandeln.

          Sprachen wie PHP haben Strings, in denen ein Zeichen nur ein Byte hat. Ein solcher String kann aber auch eine UTF-8 codierte Bytefolge speichern, und mit den mb_... Funktionen analog zu StringView.js als Unicode-String verarbeitet werden.

          Ach so. Eine Glyphe ist klassisch die visuelle Darstellung eines Zeichens gemäß dem gewählten Font. Im Fall von Unicode gibt es auch Glyphen, die auf Grund einer Sequenz von Unicode-Zeichen gezeichnet werden. Beispiel: a und ` gibt à, a und ~ gibt ã. In diesem Fall hat Unicode auch eigene Zeichen für ã und à, es gibt, z.B. im Bereich der Smileys, aber auch etliche Glyphen die keine normalisierte Darstellung haben.

          Rolf

          --
          sumpsi - posui - clusi
          1. @@Rolf B

            Das API versteckt das vor dir.

            Schon für den sächlichen Artrikel hast du dir einen Pluspunkt verdient.

            Im Fall von Unicode gibt es auch Glyphen, die auf Grund einer Sequenz von Unicode-Zeichen gezeichnet werden.

            Gezeichnet?? Was meinst du damit?

            Beispiel: a und ` gibt à, a und ~ gibt ã.

            Nicht so ganz:

            • a und ` U+0060 GRAVE ACCENT gibt nicht à. a und ̀ U+0300 COMBINING GRAVE ACCENT gibt à.
            • a und ~ U+007E TILDE gibt nicht ã. a und ̃ U+0303 COMBINING TILDE gibt à.

            Normalisierung

            In diesem Fall hat Unicode auch eigene Zeichen für ã und à,

            #lazyweb Wie müssen eigentlich Kombinationen verarbeitet werden, die kein Unicode-Zeichen ergeben, bspw. b und ̀ U+0300 COMBINING GRAVE ACCENT?

            LLAP 🖖

            --
            „Wer durch Wissen und Erfahrung der Klügere ist, der sollte nicht nachgeben. Und nicht aufgeben.“ —Kurt Weidemann
            1. Hallo Gunnar,

              ja gut, ich wollte jetzt nicht zu sehr in die Details einsteigen.

              Eine mit \u0300 gravis-verpestete Buchstabenreihe sieht bei mir so aus - keine Ahnung ob eurer Browser das darstellen.

              #àb̀c̀d̀èf̀g̀h̀ìj̀k̀l̀m̀ǹòp̀q̀r̀s̀t̀ùv̀ẁx̀ỳz̀ÀB̀C̀D̀ÈF̀G̀H̀ÌJ̀K̀L̀M̀ǸÒP̀Q̀R̀S̀T̀ÙV̀ẀX̀ỲZ̀0̀1̀2̀3̀4̀5̀6̀7̀8̀9̀

              Erzeugt in der Browser-Konsole mit

              s = "";
              for (let x of "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
                 s = s + x + String.fromCodePoint(0x300);
              console.log(s);
              

              Man kann auch noch eine Schippe Tilden und Querbalken drauflegen, aber mit den Zahlen hat er's dann nicht so...

              #à̃̅b̀̃̅c̀̃̅d̀̃̅è̃̅f̀̃̅g̀̃̅h̀̃̅ì̃̅j̀̃̅k̀̃̅l̀̃̅m̀̃̅ǹ̃̅ò̃̅p̀̃̅q̀̃̅r̀̃̅s̀̃̅t̀̃̅ù̃̅v̀̃̅ẁ̃̅x̀̃̅ỳ̃̅z̀̃̅ À̃̅B̀̃̅C̀̃̅D̀̃̅È̃̅F̀̃̅G̀̃̅H̀̃̅Ì̃̅J̀̃̅K̀̃̅L̀̃̅M̀̃̅Ǹ̃̅Ò̃̅P̀̃̅Q̀̃̅R̀̃̅S̀̃̅T̀̃̅Ù̃̅V̀̃̅Ẁ̃̅X̀̃̅Ỳ̃̅Z̀̃̅ 0̀̃̅1̀̃̅2̀̃̅3̀̃̅4̀̃̅5̀̃̅6̀̃̅7̀̃̅8̀̃̅9̀̃̅

              Rolf

              --
              sumpsi - posui - clusi
            2. #lazyweb Wie müssen eigentlich Kombinationen verarbeitet werden, die kein Unicode-Zeichen ergeben, bspw. b und ̀ U+0300 COMBINING GRAVE ACCENT?

              So wie immer, denn das ist der Default; bei Sequenzen die kanonische äquivalente Zeichen haben, sollen die unterschiedlichen Schreibweisen nicht als unterschiedliche Bedeutung des Zeichens interpretiert werden; z.B. sollen 00C1 und 0041 0301 gleich sortiert werden, weil beide das kanonisch gleiche Zeichen „a akut“ bedeuten.

              1. Hallo usb,

                guter Hinweis.

                Rrrrrespekt nach Redmont - ich habe Excel die Worte ab̀er, abba und ablauf sortieren lassen, und tatsächlich: abba, ab̀er, ablauf!

                Chrome stellt in ["ab̀er", "abba", "ablauf"].sort() das ab̀er ans Ende, d.h. er betrachtet das kombinierende Zeichen separat. Tz...

                Rolf

                --
                sumpsi - posui - clusi
                1. Rrrrrespekt nach Redmont - ich habe Excel die Worte ab̀er, abba und ablauf sortieren lassen, und tatsächlich: abba, ab̀er, ablauf!

                  Chrome stellt in ["ab̀er", "abba", "ablauf"].sort() das ab̀er ans Ende, d.h. er betrachtet das kombinierende Zeichen separat. Tz...

                  Hast du in beiden die selben Spracheinstellungen? Im österreichischen wird z.B. das ä nach dem a einsortiert, da wäre es dann nicht unlogisch auch das b̀ nach dem b einzusortieren.

                  1. Hallo usb,

                    nee, ich hab's nur falsch gemacht. [].sort sortiert blind nach Codepunktwert, wenn man es nach Unicode-Zeichenregeln haben will braucht man einen Comparer der ein locale nutzt.

                    [ "ab̀ba", "abbau", "ablaufen", "abba", "abalone"].sort((a,b) => a.localeCompare(b, "de-DE"))
                    

                    liefert ["abalone", "abba", "ab̀ba", "abbau", "ablaufen"], auch für de-AT, de-CH, en-US oder fr-FR.

                    Wobei dieses Sortieren natürlich nicht als Vorbild geeignet ist, da fehlen Typ- und Nullprüfungen. Deswegen hab ich's gleich rot angepinselt.

                    Rolf

                    --
                    sumpsi - posui - clusi
          2. hi @Rolf B

            Nein, Nein, Nein.

            Zeichen werden durch Zahlen codiert.

            So isses. Und aus den Zahlen werden bytes mit Wertigkeiten von jeweils 0..255. localStorage.set('string',string) speichert Strings und Strings sind Bytefolgen. xhr.send(string) sendet auch keine Zahlen sondern Bytefolgen.

            Aber eigentlich wollte ich nur wissen wie @TS darauf kommt daß daß Eurozeichen vermittels zweier Zeichen kodiert wird.

            Und für Dich @Rolf B : Kodierung heißt, daß Daten das System als String (Bytefolge) verlassen. Also STDOUT & Co. Wie kommst Du eigentlich darauf daß da Zahlen rausgehen? Schreibst Du etwa Zahlen in Textdateien und erwartest daß der Editor Zeichen daraus macht?

            Und ja: StringView für PHP (nur utf-8 und nur bis 3 bytes).

            MfG

            1. Hallo pl,

              Zeichen werden durch Zahlen codiert.

              So isses. Und aus den Zahlen werden bytes mit Wertigkeiten von jeweils 0..255.

              Wenn Du doch mal die Schritte einzeln machen würdest.

              Ich hätte „Zeichen werden durch Zahlen codiert“ besser als „Zeichen werden während der Verarbeitung durch Zahlen codiert“ geschrieben. Codierung geschieht auf mehreren Ebenen. In-Memory: Zeichen als Zahlen, Storage: Zahlen als Bytefolgen

              Und manchmal erfolgt die Codierung Bytefolge <-> Zahl auch transparent, z.B. bei StringView oder den PHP mb_-Funktionen. Aber umcodieren zwischen Bytefolge und Zahl müssen sie. Sonst kommt Müll raus.

              Und für Dich @Rolf B : Kodierung heißt, daß Daten das System als String (Bytefolge) verlassen. Also STDOUT & Co. Wie kommst Du eigentlich darauf daß da Zahlen rausgehen?

              Hab ich nie behauptet. Lies nochmal genau. Und mach die Schritte EINZELN. Es gibt eine Schicht zwischen Zeichen und Bytes. WIRKLICH!

              Aber eigentlich wollte ich nur wissen wie @TS darauf kommt daß Eurozeichen vermittels zweier Zeichen kodiert wird.

              Ja, der hat auch Bytes und Codepoint (=Zahl) verwechselt. Vielleicht gibt's ja auch einen Codepoint "combining equals sign", den man einem L, Y oder C überlagern kann, für eine Not-Darstellung von Pfund, Yen und Euro 😀. Gefunden habe ich nur ein Gleichheitszeichen oben oder unten, ergibt damm Y͇ (combining equals sign below) oder Y̿ (combining double overline). DAS wären dann zwei ZEICHEN und ein GLYPH. Glaube ich jedenfalls...

              Rolf

              --
              sumpsi - posui - clusi
              1. hi @Rolf B

                Hab ich nie behauptet. Lies nochmal genau. Und mach die Schritte EINZELN. Es gibt eine Schicht zwischen Zeichen und Bytes. WIRKLICH!

                Genau: Die Kodierung. So liegt der Codepoint des € 0x20Ac zwischen zwischen 0x800 und 0x10000 und das heißt, daß dieses Zeichen mit 3 Bytes zu kodieren ist wenn die Kodierung utf-8 heißt.

                Dieser Algorithmus in PHP ($cp ist der Codepoint):

                $bytes = pack('CCC', 0xe0 + ($cp >> 12), 0x80 + (($cp >> 6) & 0x3f), 0x80 + ($cp & 0x3f ));
                

                Was diese 3 Bytes (0xE2, 0x82, 0xAC) erzeugt.

                Aber eigentlich wollte ich nur wissen wie @TS darauf kommt daß Eurozeichen vermittels zweier Zeichen kodiert wird.

                Ja, der hat auch Bytes und Codepoint (=Zahl) verwechselt.

                Nun, das Eurozeichen hat nur einen Codepoint, kein Decomposition Mapping und UTF-8-kodiert genau 3 Bytes.

                Wie @TS unter diesen Umständen auf 2 Zeichen kommt wird wohl immer sein Geheimnis bleiben.

                MfG

                1. Hallo,

                  nur dass ich das richtig verstanden habe, weil ich es interessant finde und mich leider noch nie so richtig mit dieser Thematik beschäftigt habe. Methoden wie fromCharCode() verlangen die Nummer eines Unicode-Zeichens. Mir kann egal sein, wie die JavaScript-Engine dieses Zeichen im Speicher hält, es ist nur wichtig, dass ich die Unicode-Nummer weiß. Wenn ich aber dieses Zeichen auf der Festplatte speichern möchte, brauche ich ein Encoding wie UTF-8, dass dieses Zeichen dann irgendwie in Bytefolgen gießt. Habe ich das so richtig wiedergegeben?

                  Wie @TS unter diesen Umständen auf 2 Zeichen kommt wird wohl immer sein Geheimnis bleiben.

                  Vermutlich aus dem selben Grund wie ich: Nicht besser gewusst, d.h. ich hätte auch angenommen, dass das Euro-Zeichen mit 2 Bytes codiert wird.

                  Gruß
                  Patrick

                  1. Tach!

                    nur dass ich das richtig verstanden habe, weil ich es interessant finde und mich leider noch nie so richtig mit dieser Thematik beschäftigt habe. Methoden wie fromCharCode() verlangen die Nummer eines Unicode-Zeichens. Mir kann egal sein, wie die JavaScript-Engine dieses Zeichen im Speicher hält, es ist nur wichtig, dass ich die Unicode-Nummer weiß. Wenn ich aber dieses Zeichen auf der Festplatte speichern möchte, brauche ich ein Encoding wie UTF-8, dass dieses Zeichen dann irgendwie in Bytefolgen gießt. Habe ich das so richtig wiedergegeben?

                    Ja, nur dass klassisches JavaScript nichts auf der Festplatte speichern kann. Es gibt zwar mittlerweile den LocalStorage im Browser, aber JS kann nur entsprechende API-Funktionen aufrufen und seinen String übergeben und entgegennehmen. Das Kodieren und Speichern findet in Ebenen unterhalb von Javascript statt.

                    String.fromCharCode() kann aber nur die BMP, also Zeichen unterhalb von CodePoint 65536. Für den vollen Zeichenvorrat, inklusive solch wertvoller Zeichen wie Nummer 128169 (1F4A9), muss man nicht die Funktionen mit CharCode im Namen nehmen, sondern die mit CodePoint, also String.fromCodePoint() und String.prototype.codePointAt().

                    Wie @TS unter diesen Umständen auf 2 Zeichen kommt wird wohl immer sein Geheimnis bleiben.

                    Vermutlich aus dem selben Grund wie ich: Nicht besser gewusst, d.h. ich hätte auch angenommen, dass das Euro-Zeichen mit 2 Bytes codiert wird.

                    Für Javascript hat es nur eine Nummer, den Unicode-CodePoint.

                    Man kann davon ausgehen, dass unter der Haube, also in den Tiefen der Javascript-Engine, UTF-16 oder eine vergleichbare Zwei-Byte-Kodierung zum Einsatz kommt. Damit lässt sich in wesentlichen Teilen (sprich unterhalb CodePoint 65536) einfacher hantieren als mit UTF-8 mit seiner deutlich variableren Länge, die man ständig beachten müsste. Das wären dann aber zwei Byte, nicht zwei Zeichen.

                    dedlfix.

                    1. @@dedlfix

                      Das wären dann aber zwei Byte, nicht zwei Zeichen.

                      Wie jetzt, Byte und Zeichen ist nicht dasselbe?? 😈

                      LLAP 🖖

                      --
                      „Wer durch Wissen und Erfahrung der Klügere ist, der sollte nicht nachgeben. Und nicht aufgeben.“ —Kurt Weidemann
                    2. Hallo dedlfix,

                      Man kann davon ausgehen, dass unter der Haube (…) UTF-16 (…) zum Einsatz kommt.

                      ECMAScript 2018 Spec, Abschnitt 6.1.4: ECMAScript operations that do not interpret String contents apply no further semantics. Operations that do interpret String values treat each element as a single UTF-16 code unit.

                      Also ja, man kann ganz gewiss davon ausgehen.

                      String.fromCharCode() kann aber nur die BMP, also Zeichen unterhalb von CodePoint 65536.

                      Ja. Aber da die Basic Multilingual Plane die UTF-16 Surrogatpaare enthält, kann man dank der Spec auch mit CharCodes Codepoint-Scheiße bauen.

                      let shitman = String.fromCharCode(0xd83d, 0xdca9);
                      console.log(shitman);  // 💩
                      

                      Wer Surrogatpaare nicht im Kopf berechnen kann, kann sie sich über die Gegenrichtung beschaffen.

                      let funnyChar = String.fromCodePoint(0x1F4A9);
                      console.log(funnyChar.charCodeAt(0).toString(16));  // d83d
                      console.log(funnyChar.charCodeAt(1).toString(16));  // dca9
                      

                      Rolf

                      --
                      sumpsi - posui - clusi
                  2. Hallo,

                    nur dass ich das richtig verstanden habe, weil ich es interessant finde und mich leider noch nie so richtig mit dieser Thematik beschäftigt habe. Methoden wie fromCharCode() verlangen die Nummer eines Unicode-Zeichens. Mir kann egal sein, wie die JavaScript-Engine dieses Zeichen im Speicher hält, es ist nur wichtig, dass ich die Unicode-Nummer weiß. Wenn ich aber dieses Zeichen auf der Festplatte speichern möchte, brauche ich ein Encoding wie UTF-8, dass dieses Zeichen dann irgendwie in Bytefolgen gießt. Habe ich das so richtig wiedergegeben?

                    Ja, fast richtig. Wobei utf-8 nur eine von mehreren Möglichkeiten ist, Zeichen zu kodieren. Was JS betrifft: Es gibt:

                    fromCharCode|fromCodePoint charCodeAt|codePointAt

                    wobei die Methods der 2. Spalte zeichenorientiert auf die UTF-8-Kodierung/Codepoint/Unicode zugeschnitten sind. Die Methoden der 1. Spalte hingegen arbeiten sowohl byteorientiert als auch zeichenorientiert.

                    fromCharCode(kleiner 0xFF) wird JS als byte interpretieren, fromCharCode(größer 0xFF) als Zeichen. Auf jeden Fall wird JS einen str = String.fromCodePoint(cp) als Zeichen interpretieren und nicht als Bytefolge.

                    MfG

                    PS: console.log(String.fromCharCode(0xFFFF).length); zeigt 1. D.h., JS meint 1 Zeichen aber es sind 2 bytes. console.log(String.fromCharCode(0xFF).length); zeigt ebenfalls 1 aber es ist eben nur ein byte.

                    1. Hallo pl,

                      NEIIIN!

                      Die charCode Methoden arbeiten auf 16-bit (UTF-16) Werten, die codePoint-Methoden kennen die UTF16 Surrogatpaare und verwenden daher Werte bis 0x10ffff.

                      Dein readAsBinaryString, worüber wir letztens sprachen, liest eine Bytesequenz in einen String, der laut Spec aus 16-bit Werten besteht, die in diesem Fall aber nur mit Werten 0-255 belegt sind.

                      fromCharCode(n) mit n<256 wird von JS NICHT als Byte interpretiert. Sondern immer als Zeichen, gespeichert in 16 Bit. Solange Du innerhalb des String-Objekts bist (sei es nun das String-Objekt oder der primitive string-Typ), hantierst Du nicht mit Bytes.

                      Rolf

                      --
                      sumpsi - posui - clusi
                      1. hi @Rolf B

                        fromCharCode(n) mit n<256 wird von JS NICHT als Byte interpretiert. Sondern immer als Zeichen, gespeichert in 16 Bit.

                        Es sind nur 8 Bit (1 byte), nicht 16

                        var s = String.fromCharCode(195,164,228);
                        console.log(s, s.length);
                        
                        // siehst Du
                        // ää 3
                        

                        .length ist also die Anzahl der bytes die dabei rauskommen. Ob JS intern da mit 2 byte je byte operiert (UTF16) ist mir vollkommen egal. Ich habe hier Binaries im MB Bereich und die sind absolut bytegenau.

                        MfG

                        PS: Die eigentliche Frage warum JS mit String.fromCharCode(195,164) kein ä zeigt ist übrigens immer noch offen.

                        1. @@pl

                          PS: Die eigentliche Frage warum JS mit String.fromCharCode(195,164) kein ä zeigt ist übrigens immer noch offen.

                          Nein, die ist längst geklärt.

                          Die Frage, die immer noch offen ist, ist die, ob du das jemals verstehen wirst, was es mit Zeichen, Codepoints und Zeichencodierungen auf sich hat.

                          Obwohl – vielleicht ist auch diese Frage längst geklärt.

                          LLAP 🖖

                          --
                          „Wer durch Wissen und Erfahrung der Klügere ist, der sollte nicht nachgeben. Und nicht aufgeben.“ —Kurt Weidemann
                          1. hi @Gunnar Bittersmann

                            natürlich ist meine Frage längst geklärt. Allerdings hast Du nicht das Geringste dazu beigetragen!

                            MfG

                            1. @@pl

                              natürlich ist meine Frage längst geklärt. Allerdings hast Du nicht das Geringste dazu beigetragen!

                              Nicht?

                              LLAP 🖖

                              --
                              „Wer durch Wissen und Erfahrung der Klügere ist, der sollte nicht nachgeben. Und nicht aufgeben.“ —Kurt Weidemann
                        2. Hallo pl,

                          Es sind nur 8 Bit (1 byte), nicht 16

                          Falsch.

                          var s = String.fromCharCode(195,164,228);
                          console.log(s, s.length);
                          
                          // siehst Du
                          // ää 3
                          

                          Ich sehe, dass der String 3 Zeichen enthält. Und ich weiß, dass diese Zeichen JS-intern 16-bittig gespeichert werden.

                          Das, was passiert wenn Du diesen String in einen Blob legst und ihn per FileReader und seine UTF-8 Codierung mit readAsBinaryString abholst, hat damit nichts zu tun.

                          .length ist also die Anzahl der bytes die dabei rauskommen.

                          Nein. Die Anzahl der Zeichen.

                          Ob JS intern da mit 2 byte je byte operiert (UTF16) ist mir vollkommen egal.

                          Schade. Weil genau das das Thema dieser Diskussion ist.

                          Ich habe hier Binaries im MB Bereich und die sind absolut bytegenau.

                          Sie werden bytegenau als ein Zeichen pro Byte gespeichert. D.h. der „binary string“, den Du aus deinem Binary erhältst, belegt doppelt so viele Bytes wie dein Binary. Das kann Dir egal sein solange es nur ein paar MB sind; es kann Dir nicht egal sein, wenn der Browser 32-bittig läuft und Du in den Bereich von hunderten von MB kommst.

                          PS: Die eigentliche Frage warum JS mit String.fromCharCode(195,164) kein ä zeigt ist übrigens immer noch offen.

                          Nein. Du gibst ihm zwei Bytes eines UTF-8 Encodings, aber führst die Decodierung dieses Encodings nicht durch. Statt dessen bekommst Du gemäß Spec ein JavaScript-Objekt, in dem sich neben Verwaltungsinformationen 4 Bytes mit den Werten 195,0,164,0 befinden (auf einer little-endian Maschine). Es ist ein String in UTF-16 Codierung. Wenn Du UTF-8 decodieren willst, gibt es den TextDecoder, der aber nicht überall verfügbar ist, manuelles Gefummel mit Escape/Unescape-Techniken oder manuelle Interpretation des Encodings (wie Du es schon gezeigt hast). Manuelle Methoden kannst Du auch indirekt anwenden, mittels geeigneter JS Libraries (mutmaßlich StringView.js).

                          Rolf

                          --
                          sumpsi - posui - clusi
                          1. hi @Rolf B

                            danke für Deine Info's. Mit Sicherheit kommen wir nun zur Frage der Optimierung, RAM und CPU Gefälligkeit. So wäre die Alternative zum BinaryString Base64, womit die zu speichernde Datenmenge sogar geringfügig kleiner wird. Jedoch ist der Binary String nicht doppelt so lang wie die Binary, was daran liegt, daß es auch bytes mit Wertigkeiten unter 0x80 gibt.

                            Mit Base64 allerdings geht auf meiner alten Kiste die CPU Auslastung durch die Decke, was beim Binary String nicht der Fall ist. In Sachen RAM ergibt sich ein beiden Fällen nur ein Burst der vom Systemmonitor kaum bemerkt wird.

                            Ich tendiere also deutlich zum Binary String und Du?

                            MfG

                            1. Hallo pl,

                              wenn wir von Optimierung anfangen, müsste ich wissen, was Du eigentlich tust. Bisher haben wir abstrakt über Unicode-Darstellungen gesprochen und ein Beispiel-JS zum Konvertieren in einen „binary string“.

                              Upload eines Files per Ajax wäre sicherlich per XmlHttpRequest.send(file) einfacher, bzw. wenn Du ein Filepaket hochladen willst, durch den send() eines FormData-Objekts in das Du die Files einstellst. Dann läuft alles nativ im Hintergrund, d.h. vor allem SCHNELL, und Du bist mit der Arbeit fertig. Deine Server-Perle ist damit sicherlich auch glücklich.

                              Was machst Du denn eigentlich mit deinem Binary String, wenn Du ihn in den Fingern hast. Wie geht die Verarbeitung weiter?

                              Rolf

                              --
                              sumpsi - posui - clusi
                              1. Hi @Rolf B

                                danke der Nachfrage! localStorage speichert leider nur Strings, das ist der einzige Grund der Begehrlichkeit. Es geht also nur ums Speichern wobei die Datenquelle File, Blob oder ArrayBuffer sein kann.

                                MfG

                                1. Hallo pl,

                                  verstehe. Und wie machst Du das mit dem Rückweg? Aus dem LocalStorage bekommst Du ja den den readAsBinaryStringifizierten Wert zurück, der will wieder ein ArrayBuffer werden. Oder ein Blob. Machst Du das mit dem Iterator-Dings, das ich vorgestern als Schuss aus der Hüfte vorschlug? Oder hast Du was besseres gefunden?

                                  Rolf

                                  --
                                  sumpsi - posui - clusi
                                  1. hi @Rolf B

                                    aus localStorage bekomme ich den String. Hierzu 2 Funktionen:

                                    // Binary String to ArrayBuffer
                                    function str2ab(str) {
                                      var buf = new ArrayBuffer(str.length);
                                      var bufView = new Uint8Array(buf);
                                      for (var i=0; i<str.length; i++) {
                                        bufView[i] = str[i].charCodeAt(0);
                                      }
                                      return buf;
                                    }
                                    
                                    // Binary String to Uint8Array
                                    function str2uha(str) {
                                      var buf = new ArrayBuffer(str.length);
                                      var uha = new Uint8Array(buf);
                                      for (var i=0; i<str.length; i++) {
                                        uha[i] = str[i].charCodeAt(0);
                                      }
                                      return uha;
                                    }
                                    

                                    Und umgekehrt kommts Dir evntl bekannt vor:

                                    // Arraybuffer to BinaryString
                                    function ab2str(ab){
                                        var dv = new DataView(ab);
                                        var offs = 0;
                                        var binstr = '';
                                        while (offs < dv.byteLength ){
                                            binstr += String.fromCharCode(dv.getUint8(offs));
                                            offs += 1;
                                        }
                                        return binstr;
                                    }
                                    
                                    

                                    Der Rest ist Builtin. MfG

                            2. Zum Testen

                              Base64

                              String

                              Mir scheint, mit String läufts flüssiger, RAM und CPU gefälliger.

                              Bitte mal fredbeck, mfg

                              1. Hallo pl,

                                das ist subjektiv schwer zu sehen, eine integrierte Laufzeitmessung wäre praktisch. Den Speicherverbrauch erkenne ich nicht richtig.

                                Aber mir scheint, dein base64-Encoder hinkt. Mit new String() erzeugst Du einen Wrapper um den primitiven string, und bei jedem Zugriff muss er über den Wrapper laufen. Das macht deinen b64a-String sehr langsam.

                                Ersetze mal b64a: new String('ABC..89+/=') durch b64a: 'ABC..89+/')

                                Die Laufzeit drittelt sich fast. Dein Decoder leidet auch an Stringzugriffen, da geht was mit Uint8Array und Lookup-Tables.

                                Guck mal hier.

                                Zuerst Deine Klasse, dann meine, dann etwas Testcode. Da ist eine Zuweisung an TestObjekt, da wählst Du aus was verwendet wird. Testgröße gibt an, wie groß der Teststring wird (Testgröße+1 verdoppelt den Teststring). Laufzeitmessungen erscheinen in der Konsole.

                                Rolf

                                --
                                sumpsi - posui - clusi
                                1. Tach!

                                  Guck mal hier.

                                  btoa() ist kaputt. Das kann nur Strings mit den Zeichen der CodePoints 0..255 verarbeiten.

                                  dedlfix.

                                  1. Hallo dedlfix,

                                    das sagen viele, aber die Funktion ist nicht kaputt, sondern funktioniert nach Vorgabe.

                                    Meines Wissens ist base64-Codierung definiert als "Verteile 3 Bytes auf 4". Es ist also korrekt, dass btoa keine Unicodezeichen jenseits von \u00ff annimmt. Dafür muss man den Unicode-String erstmal UTF-8 codieren, dann hat man eine Bytesequenz und btoa ist wieder anwendbar.

                                    Das Blöde an der Sache ist, dass JavaScript nur einen sehr umständlichen Weg bietet, um an die UTF-8 Codierung einer Ressource heranzukommen. Über Blob und FileReader ist es noch am einfachsten, mit dem Nachteil des „binary string“, der zu 50% aus Totbytes besteht. Eine native Implementierung, die einen ArrayBuffer base64 codiert, scheint zu fehlen. Oder ich bin zu blöd es zu finden :)

                                    PLs Anliegen, eine binäre Ressource serialisiert im LocalStorage abzulegen, ist also nicht so ganz trivial. Vielleicht ist das Absicht, und der LocalStorage ist dafür nicht vorgesehen.

                                    Rolf

                                    --
                                    sumpsi - posui - clusi
                                    1. Tach!

                                      das sagen viele, aber die Funktion ist nicht kaputt, sondern funktioniert nach Vorgabe.

                                      Ja, so herum stimmt es eher, aber dann muss ich umformulieren, dass du es nicht so verwendet hast, dass es gemäß Vorgabe funktionieren kann.

                                      PLs Anliegen, eine binäre Ressource serialisiert im LocalStorage abzulegen, ist also nicht so ganz trivial. Vielleicht ist das Absicht, und der LocalStorage ist dafür nicht vorgesehen.

                                      Das ist vermutlich der eigentliche Knackpunkt. Warum soll ein Bild im LocalStorage abgelegt werden, dass von der Quelle bezogen werden kann? Warum will man das dezentral lagern? (Bild bitte als Synonym für alle Daten betrachten, die serverseitig erzeugt wurden.)

                                      dedlfix.

                                      1. Hallo dedlfix,

                                        dass du es nicht so verwendet hast, dass es gemäß Vorgabe funktionieren kann.

                                        Hm, eigentlich nicht, aber funktionieren kann es hier. Ich hatte ja einen String aus ASCII-Zeichen. Das war NUR im Testtreiber, nicht in der Base64-Implementierung. Hätte ich mit einem Unicode-String getestet, dann hätte ich vorher UTF-8 codieren müssen. Aber darum ging's ja nicht, sondern nur darum, irgendwie einen fetten Blob zu erschaffen. Er muss ja nicht gleich Dead Ringer For Love oder Somewhere over the Rainbow singen 😂

                                        Rolf

                                        --
                                        sumpsi - posui - clusi
                                    2. @Rolf B

                                      das sagen viele, aber die Funktion ist nicht kaputt, sondern funktioniert nach Vorgabe.

                                      Meines Wissens ist base64-Codierung definiert als "Verteile 3 Bytes auf 4". Es ist also korrekt, dass btoa keine Unicodezeichen jenseits von \u00ff annimmt.

                                      Base64 hat mit Unicode überhaupt nichts zu tun. Base64 ist aus UUencode (in Perl Builtin und als u Schablone für pack/unpack implementiert) hervorgegangen und hat das Ziel, bytes beliebiger Wertigkeiten auf den Zeichenvorrat des Base64-Alphabets, was aus 64 Zeichen besteht, daher der Name, abzubilden. Das Mittel zum Zweck sind Bitoperationen.

                                      Die Länge einer Binary vergrößert sich durch die Base64 Kodierung um den Faktor 4/3.

                                      PLs Anliegen, eine binäre Ressource serialisiert im LocalStorage abzulegen, ist also nicht so ganz trivial.

                                      Doch, ist es. Es wird ja nur ein String erzeugt aus Oktettenwertigkeiten die in Containern wie Uint8Array oder ArrayBuffer vorliegen. Angewandt wird dafür String.fromCharCode(x) ganz genauso wie man das in Perl mit chr(x) für jedes einzelne Byte tun würde.

                                      MfG

                                      1. Tach!

                                        Meines Wissens ist base64-Codierung definiert als "Verteile 3 Bytes auf 4". Es ist also korrekt, dass btoa keine Unicodezeichen jenseits von \u00ff annimmt.

                                        Base64 hat mit Unicode überhaupt nichts zu tun.

                                        Wenn du nicht immer ignorieren würdest, dass Javascript-Strings zeichenorientiert aufgebaut sind, denn würde dir vielleicht auch klar werden, was hier das Problem ist. Die Funktion btoa() nimmt sich ein Zeichen (und kein Byte), bestimmt davon die CodePoint-Nummer und versucht dann daraus die Base64-Ausgabe zu erstellen. Da der Base64-Algorithmus aber nur mit Werten von 0..255 umgehen kann, gibts hier ein Problem mit Zeichen oberhalb von CodePoint 255.

                                        Zitat MDN: The WindowOrWorkerGlobalScope.btoa() method creates a base-64 encoded ASCII string from a String object in which each character in the string is treated as a byte of binary data.

                                        Note: Since this function treats each character as a byte of binary data, regardless of the number of bytes which actually make up the character, an InvalidCharacterError exception is thrown if any character's code point is outside the range 0x00 to 0xFF.

                                        dedlfix.

                                        1. Tach!

                                          Note: Since this function treats each character as a byte of binary data, regardless of the number of bytes which actually make up the character, an InvalidCharacterError exception is thrown if any character's code point is outside the range 0x00 to 0xFF.

                                          Ok wir übersetzen das mal:

                                          Da diese Funktion jedes Zeichen als Binärdatenbyte behandelt, wird unabhängig von der Anzahl der Bytes, aus denen das Zeichen besteht, eine InvalidCharacterError-Ausnahme ausgelöst, wenn der Codepunkt eines Zeichens außerhalb des Bereichs 0x00 bis 0xFF liegt.

                                          Also, mal ehrlich, von Fachmann zu Fachmann, soll das ein Witz sein!? Das sind ja mindestens 3 Widersprüche in einem Satz! Da habe ich meine Library schneller in den Editor getippt als über solch einen Schwachsinn nachgedacht.

                                          MfG

                                          PS: Es gibt immer Gründe für eigene Entwicklungen!

                                          1. Tach!

                                            Also, mal ehrlich, von Fachmann zu Fachmann, soll das ein Witz sein!? Das sind ja mindestens 3 Widersprüche in einem Satz!

                                            Die da wären?

                                            dedlfix.

                                          2. Hallo pl,

                                            das ist nicht widersprüchlich, das ist einfach die Beschreibung der Einschränkungen, unter denen btoa funktioniert. Du hast ja mir ja beigestimmt, dass Base64 zum Codieren von Bytes gilt. Das muss man den Leuten, die mit Unicode sozialisiert wurden und vor denen Base64 schön in den Tiefen des Netzwerk-Protokolls versteckt wird, nur klar machen. Dazu diese Beschreibung.

                                            Ich habe mein Fiddle gerade um eine Zeitmessung von btoa erweitert: Die handgemachte encode-Methode braucht über 1000ms, btoa aber nur 54. Nackig auf dem Metall rennt der Code nun mal schneller, da kommt der JS-JIT nicht mit. Das ist dann der Preis der Eigenentwicklung.

                                            Rolf

                                            --
                                            sumpsi - posui - clusi
                                            1. hi @Rolf B

                                              Ich habe mein Fiddle gerade um eine Zeitmessung von btoa erweitert: Die handgemachte encode-Methode braucht über 1000ms, btoa aber nur 54.

                                              Das ist ganz toll, nützt aber nichts.

                                              Das ist dann der Preis der Eigenentwicklung.

                                              Der Preis der Eigenentwicklung ist, daß sie funktioniert!

                                              MfG

                                              PS: Die Verwandschaft von UUencode und Base64

                                              # Binary Eurozeichen erzeugen
                                              my $bin = chr(0xE2).chr(0x82).chr(0xAC);
                                              
                                              # Base64 Kodierung
                                              my $b64 = encode_base64($bin);                # Base64 4oKs
                                              
                                              # Translate to UUencode & Decode
                                              $b64 =~ tr#A-Za-z0-9+/##cd;                   # remove non-base64 chars
                                              $b64 =~ tr#A-Za-z0-9+/# -_#;                  # convert to uuencoded format
                                              my $len = pack("c", 32 + 0.75*length($b64));  # compute length byte
                                              print unpack("u", $len . $b64);               # Binary €
                                              

                                              Qualle

                                            2. hi @Rolf B

                                              MDN zu window.btoa: Erzeugt eine Base-64-kodierten ASCII-Zeichenkette aus einer "Zeichenkette" von Binärdaten.

                                              PS: mit BinaryString funtioniert auch window.btoa(binary_string) korrekt. Nur mus man den BinaryString ersteinmal haben.

                                              Siehe auch womit wir wieder bei String.fromCharCode() wären.

                                              Wobei der ebenda gezeigte Umweg über encodeURIComponent() zwar auch ganz toll aber völlig überflüssig ist.

                                              1. Hallo pl,

                                                Nur mus man den BinaryString ersteinmal haben.

                                                Ja. Das hatte ich auch schon überlegt. Aber das hängt jetzt von deiner Ausgangsbasis ab. Wenn das eine lokale Datei ist, die in einem <input type=file> selektiert wurde, ist das schon ein Blob (File=Blob). Wenn Du die Ressource per Fetch API vom Server holst (nicht im IE, keine Ahnung ob man das polyfillen kann), kannst Du auf den Response-Objekt aussuchen ob Du einen Blob oder einen ArrayBuffer haben willst. Aber im XMLHttpRequest kannst Du auch zwischen Blob und ArrayBuffer wählen, wenn Du den responseType vorher setzt.

                                                Ich hatte heute morgen mein Performance-Fiddle nochmal umgeschrieben. Es ist jetzt Promise-gesteuert, was den serialisierten Umgang mit FileReader einfacher macht, und da ist jetzt auch eine Messung von btoa drin. Das Ding ist grob acht- bis zehnmal schneller als der handgemachte Encode, auch wenn man die Konvertierung ArrayBuffer->BinaryString mitmisst.

                                                Rolf

                                                --
                                                sumpsi - posui - clusi
                                                1. problematische Seite

                                                  hi @Rolf B

                                                  den MDN Vorschlag hab ich doch gleich hier verwurstet. Das macht direkt aus einer Zeichenkette einen Binary String ohne Filereader.

                                                  Aber JS kennt ja keine Bytes, sondern nur Zeichen nunja. Ich für meinen Teil bleibe bei meinen Begrifflichkeiten, die habe ich von Perl.

                                                  MfG

                                                  1. problematische Seite

                                                    Hello,

                                                    Aber JS kennt ja keine Bytes, sondern nur Zeichen nunja. Ich für meinen Teil bleibe bei meinen Begrifflichkeiten, die habe ich von Perl.

                                                    Layer 6 + 7
                                                    Wo findest Du da Bytes?

                                                    Glück Auf
                                                    Tom vom Berg

                                                    --
                                                    Es gibt nichts Gutes, außer man tut es!
                                                    Das Leben selbst ist der Sinn.
                                      2. Base64 ist aus UUencode (in Perl Builtin und als u Schablone für pack/unpack implementiert) hervorgegangen

                                        nein, Base64 stammt von PEM ab und das ist älter als perl: „This encoding is virtually identical to the one used in Privacy Enhanced Mail (PEM) applications, as defined in RFC 1421.“ - https://tools.ietf.org/html/rfc2045#page-24

                                        1. Base64 ist aus UUencode (in Perl Builtin und als u Schablone für pack/unpack implementiert) hervorgegangen

                                          nein, Base64 stammt von PEM ab und das ist älter als perl: „This encoding is virtually identical to the one used in Privacy Enhanced Mail (PEM) applications, as defined in RFC 1421.“ - https://tools.ietf.org/html/rfc2045#page-24

                                          PEM und MIME beschreiben kein Kodierungsverfahren sondern die Anforderung.

                                          UUencode, Unix-to-Unix encode, ist so alt wie Unix und auch älter als Base64.

                                          MfG

                                          --
                                          Prüfungsfrage bei Cisco: Nennen Sie eine RFC.
                                          1. nein, Base64 stammt von PEM ab und das ist älter als perl: „This encoding is virtually identical to the one used in Privacy Enhanced Mail (PEM) applications, as defined in RFC 1421.“ - https://tools.ietf.org/html/rfc2045#page-24

                                            PEM und MIME beschreiben kein Kodierungsverfahren sondern die Anforderung.

                                            Da hättest du den Links vielleicht einmal folgen sollen und hättest direkt was gelernt. In beiden RFC werden u.a. Kodierungsverfahren definiert.

                                            UUencode, Unix-to-Unix encode, ist so alt wie Unix

                                            uuencode ist zwar älter als ich, aber nur von 1980, BSD 4 war wohl das erste UNIX mit uuencode.

                                            und auch älter als Base64.

                                            Ja, aber nicht der Vorfahr von Base64; möglich dass PEM von uuencode inspiriert war, aber dazu habe ich bisher nix gefunden.

                                2. hit @Rolf B

                                  dank für Dein feedback! Base64.js geändert, new String ersetzt durch ''. Das ergibt eine gefühlte Verbesserung. Ansonsten ist mit Base64 der CPU Burst deutlich größer und hat 2 peaks die wohl encode/decode geschuldet sind.

                                  Die Stingvariante hat nur einen peak und sieht im Systemmonitor deutlich ausgeglichener aus. Das Test-Image hat eine Länge 2.295.557 bytes.

                                  MfG

                                  PS: Meine Bas64.js ist binary safe. Du kannst sie gerne weiter verbessern.

                                3. Guck mal hier.

                                  Kleiner Tipp: Mit console.profile erhälst du einen ausführlichen Report, den du mit den Dev-Tools interaktiv auswerten kannst. So kannst du dir die manuellen Messungen sparen.

                                  U.a. findet man dort auch diese praktische Ansicht:

                                  Chrome DevTools Beispiel für console.profile

                                  1. Hallo 1unitedpower,

                                    Kleiner Tipp: Mit console.profile erhälst du einen ausführlichen Report, den du mit den Dev-Tools interaktiv auswerten kannst. So kannst du dir die manuellen Messungen sparen.

                                    Oi - kannte ich tatsächlich auch noch nicht. Neat, danke für den Hinweis!

                                    LG,
                                    CK

                                  2. Hallo 1unitedpower,

                                    Superhinweis, danke!

                                    Rolf

                                    --
                                    sumpsi - posui - clusi
                      2. moin @Rolf B

                        fromCharCode(n) mit n<256 wird von JS NICHT als Byte interpretiert. Sondern immer als Zeichen, gespeichert in 16 Bit. Solange Du innerhalb des String-Objekts bist (sei es nun das String-Objekt oder der primitive string-Typ), hantierst Du nicht mit Bytes.

                        Ein Blob bringt da Klarheit wieviele bytes es sind:

                        var s = String.fromCharCode(0xA);
                        var b = new Blob([s]);
                        console.log(b.size);    // 1 byte
                        

                        also keine 16 bit sondern nur 8. Wenn es UTF16 wäre, hätte der Blob eine Länge von 2 bytes!

                        MfG

                        1. Hallo pl,

                          Ein Blob bringt da Klarheit wieviele bytes es sind:

                          var s = String.fromCharCode(0xA);
                          var b = new Blob([s]);
                          console.log(b.size);    // 1 byte
                          

                          also keine 16 bit sondern nur 8. Wenn es UTF16 wäre, hätte der Blob eine Länge von 2 bytes!

                          🤦

                          LG,
                          CK

                          1. @@Christian Kruse

                            🤦

                            Wenn 1000 Worte nicht helfen, ein Bild sagt mehr. 😏

                            LLAP 🖖

                            --
                            „Wer durch Wissen und Erfahrung der Klügere ist, der sollte nicht nachgeben. Und nicht aufgeben.“ —Kurt Weidemann
                            1. Hallo Gunnar,

                              ein kleines Rechteck sagt mir leider gar nichts (Win7 und Android 6). Welcher Unicode-Codepoint wurde da gewählt? Mr. Shit ist es nicht, den kennt mein Browser.

                              Oder war das kleine Rechteck das beabsichtigte Symbol?

                              Rolf

                              --
                              sumpsi - posui - clusi
                              1. Hallo

                                ein kleines Rechteck sagt mir leider gar nichts (Win7 und Android 6). Welcher Unicode-Codepoint wurde da gewählt? Mr. Shit ist es nicht, den kennt mein Browser.

                                Oder war das kleine Rechteck das beabsichtigte Symbol?

                                Ne, es ist der Facepalm.

                                Tschö, Auge

                                --
                                Eine Kerze stand [auf dem Abort] bereit, und der Almanach des vergangenen Jahres hing an einer Schnur. Die Herausgeber kannten ihre Leser und druckten den Almanach auf weiches, dünnes Papier.
                                Kleine freie Männer von Terry Pratchett
                                1. @@Auge

                                  ein kleines Rechteck sagt mir leider gar nichts (Win7 und Android 6). Ne, es ist der Facepalm.

                                  Immer die Leute mit ihren minderwertigen Systemen. m(

                                  😉

                                  LLAP 🖖

                                  --
                                  „Wer durch Wissen und Erfahrung der Klügere ist, der sollte nicht nachgeben. Und nicht aufgeben.“ —Kurt Weidemann
                        2. Tach!

                          Ein Blob bringt da Klarheit wieviele bytes es sind:

                          var s = String.fromCharCode(0xA);
                          var b = new Blob([s]);
                          console.log(b.size);    // 1 byte
                          

                          also keine 16 bit sondern nur 8. Wenn es UTF16 wäre, hätte der Blob eine Länge von 2 bytes!

                          Falsche Messmethode, falsche Schlussfolgerung. Eine Aussage zum String kann mit dem Blob nicht getroffen werden, denn der Blob-Konstruktor kodiert den String als UTF-8.

                          MDN zum Blob-Konstruktor: „Parameters: array is an Array of ArrayBuffer, ArrayBufferView, Blob, DOMString objects, or a mix of any of such objects, that will be put inside the Blob. DOMStrings are encoded as UTF-8.“

                          Der letzte Satz ist ein bisschen uneindeutig. Folgt man dem dortigen Link zur Spezifikation findet man darin „Append the result of UTF-8 encoding s to bytes.“ Das heißt also nicht, dass DOMStrings UTF-8-kodiert sind, sondern dass das Ergebnis der UTF-8-Kodierung von s (eines der Argumente des o.g. Arrays) zum Ergebnis (bytes: „Let bytes be an empty sequence of bytes“) hinzugefügt wird.

                          MDN zu DOMString: „DOMString is a UTF-16 String. As JavaScript already uses such strings, DOMString is mapped directly to a String.“

                          Web IDL zu DOMString (wobei IDL für interface description language steht. Damit werden die Schnittstellen beschrieben, die der Browser zur Verfügung stellt, also der Teil, mit dem Javascript-Code interagiert, wenn man Dinge außerhalb des Javascript-Wirkungsbereiches zu erledigen hat): „The DOMString type corresponds to the set of all possible sequences of code units. Such sequences are commonly interpreted as UTF-16 encoded strings [RFC2781] although this is not required.“

                          Eine Definition von „code unit“ findet man im Glossar vom Unicode-Konsortium: „The minimal bit combination that can represent a unit of encoded text for processing or interchange. The Unicode Standard uses 8-bit code units in the UTF-8 encoding form, 16-bit code units in the UTF-16 encoding form, and 32-bit code units in the UTF-32 encoding form.“

                          Es hängt also von der konkreten Implementation der Javascript-Engine ab, was da intern verwendet wird. Meist ist es wohl UTF-16.

                          Es bleibt nach wie vor dabei, dass diese Interna für das Arbeiten mit Javascript nicht weiter relevant sind (wenn man nicht gerade einen Schichtensalat zu produzieren versucht). Was an welcher Stelle nach außen hin sichtbar ist, hängt davon ab, was das jeweilige Objekt/Funktion/Methode daraus macht, das man verwendet, und verwenden muss, um mit der Außenwelt zu kommunizieren.

                          dedlfix.

                        3. Hallo pl,

                          bei der Ablage in einem Blob wird ein String zu UTF-8 umkodiert. Hatten wir schon.

                          Rolf

                          --
                          sumpsi - posui - clusi
                          1. hi @Rolf B

                            natürlich ist es utf8. Und obwohl JS in String.fromCharCode(0xE2,0x82,0xAC) anstatt des Eurozeichen 3 einzelne utf-8-Zeichen zu erkennen versucht, liefert die Rückrechnung

                            var s = String.fromCharCode(0xE2,0x82,0xAC);
                            for(var i = 0; i < s.length; i++){
                                console.log( s[i].charCodeAt(0) );
                            }
                            

                            dennoch die richtigen Oktettenwertigkeiten für ein utf-8-kodiertes Eurozeichen. MfG

                            1. Hallo pl,

                              Nein. String.fromCharCode(0xE2,0x82,0xAC) erkennt 3 einzelne UTF-16 Zeichen, weil das die Spec-konforme interne Darstellung von JavaScript-Strings ist. Mit UTF-8 hat diese Funktion nichts am Hut.

                              Rolf

                              --
                              sumpsi - posui - clusi
                              1. @@Rolf B

                                Nein. String.fromCharCode(0xE2,0x82,0xAC) erkennt 3 einzelne UTF-16 Zeichen

                                Ähm, nein. Es gibt ebensowenig UTF-16-Zeichen wie UTF-8-Zeichen. Du meinst: Unicode-Zeichen, kurz: Zeichen?

                                LLAP 🖖

                                --
                                „Wer durch Wissen und Erfahrung der Klügere ist, der sollte nicht nachgeben. Und nicht aufgeben.“ —Kurt Weidemann
                                1. Tach!

                                  Nein. String.fromCharCode(0xE2,0x82,0xAC) erkennt 3 einzelne UTF-16 Zeichen

                                  Ähm, nein. Es gibt ebensowenig UTF-16-Zeichen wie UTF-8-Zeichen. Du meinst: Unicode-Zeichen, kurz: Zeichen?

                                  Nicht ganz, weil diese Funktion nur Zeichen bis CodePoint 65535 erkennt. Das ist eine alte Funktion, aus der Zeit als es nur die BMP gab und Javascript dafür gestrickt wurde. Das moderne Pendant dazu ist String.fromCodePoint() und hat eine etwas eingeschränktere Verfügbarkeit.

                                  dedlfix.

                                2. Hallo Gunnar,

                                  ähm, nein, ich meinte eben NICHT Unicode-Zeichen. Das war nur bis August 1999 so. Im September 1999 kamen mit Unicode 3.0 die Surrogatpaare ins Spiel und JavaScript war mit „ein Unicode-Zeichen passt in 16 Bits“ angeschmiert, genau wie Java und das gerade im Backofen befindliche NGWS (a.k.a Microsoft.Net).

                                  Wie ich hier schreibte, bekommt fromCharCode UTF-16 Codewörter, von denen die meisten einen gültigen Unicode-Zeichencode darstellen. Aber wenn ich die Nummern von Surrogaten übergebe, dann entsteht das Zeichen erst mittels codePointAt.

                                  Rolf

                                  --
                                  sumpsi - posui - clusi
  3. Hi,

    warum sehe ich hier kein Eurozeichen sondern 3 Andere?

    console.log(String.fromCharCode(0xe2,0x82,0xac) );
    

    weil die Methode fromCharCode heißt, nicht fromUtf8Bytes.

    cu,
    Andreas a/k/a MudGuard

  4. Hallo pl,

    ich hab Dir schon öfter mal das Uint8Array als geeigneten Datentyp empfohlen. Es gibt im File API keinen FileWriter mit einer Methode writeFromBinaryString.

    utf8euro = Uint8Array.from([0xe2, 0x82, 0xac ]);
    euro = new TextDecoder().decode(utf8euro);
    

    Du kannst für einen Roundtrip String -> „Binary String“ -> String aber auch einen kleinen Helper bauen (den Kompatibilitätscheck überlasse ich Dir) und das Ganze damit relativ kompakt darstellen:

    // Helper zum Iterieren über die CharCodes eines String
    function* iterateCharCodes(s) {
       for (let c of s) yield c.charCodeAt(0);
    }
    
    let hello = "Hällo Wörld für 217€";
    let hBlob = new Blob([hello]);
    let fr = new FileReader();
    fr.onload = function() {
       console.log("„Binary String“: " + fr.result);
       
       let ui = Uint8Array.from(iterateCharCodes(fr.result));
    
       console.log("Reconstructed String: " + (new TextDecoder().decode(ui)));
    };
    fr.readAsBinaryString(hBlob);
    

    Der TextDecoder will dummerweise etwas Bufferoides haben und nimmt den Iterator nicht direkt an.

    Mit iterateCharCodes kannst Du einen beliebigen String („binary string“ oder jeder sonst) in seine Zeichen zerlegen und einen Iterator über die Unicode Codepoints bekommen. Den Iterator kannst Du mit for...of konsumieren oder an Factorymethoden wie Uint8Array.from übergeben.

    Rolf

    --
    sumpsi - posui - clusi
    1. hi @Rolf B

      ich interpretiere das auch so wie Du, daß JS den Sting als Binary String auffasst, also als Folge von Bytes und nicht als Folge von Zeichen.

      In Perl sähe das so aus:

      $bytes = pack "CCC", 0xe2, 0x82, 0xac;
      # oder byte für byte
      chr(0xe2).chr(0x82).chr(0xac);
      

      Mitteles StringView() macht JS aus der Bytefolge eine Zeichenfolge. In dieser Lib ist also die Umrechnung von Bytes in Codepoint und umgekehrt implementiert. Siehe ebenda.

      MfG