JürgenB: Regex - Worttrennzeichen

0 47

Regex - Worttrennzeichen

JürgenB
  • javascript
  • regex
  1. 2
    Peter
    1. 0
      JürgenB
  2. 0
    Rolf B
    1. 0
      JürgenB
  3. 0
    Raketenbahnregulator
    1. 0
      JürgenB
      1. 2
        Raketenpilotenausbilder
        1. 0
          JürgenB
          1. 0
            Raketenpilotenausbilder
          2. 0
            Der Martin
            1. 0
              JürgenB
              1. 0
                Gunnar Bittersmann
                • internationalisierung
                1. 0
                  JürgenB
          3. 0
            Gunnar Bittersmann
            • meinung
            1. 0
              Matthias Apsel
              1. 0
                Gunnar Bittersmann
                1. 0
                  JürgenB
                  1. 0
                    Gunnar Bittersmann
                    1. 0
                      JürgenB
                      1. 0
                        Gunnar Bittersmann
                        1. 0
                          JürgenB
                        2. 0
                          Rolf B
                          1. 0
                            Gunnar Bittersmann
                            1. 0
                              Rolf B
                          2. 0
                            JürgenB
    2. 0

      (Verbesserungen)

      Raketeningrid
      1. 0

        (hoffentlich) letzte Verbesserungen

        Raketeningrid
        1. 0
          Rolf B
          1. 2
            Gunnar Bittersmann
            1. 0
              Raketeningrid
              1. 0
                Gunnar Bittersmann
                1. 0
                  JürgenB
                  1. 0
                    Raketenwissenschaftler
                    1. 1
                      Mitleser 2.0
                      1. 0
                        JürgenB
                        1. 0
                          Mitleser 2.0
                          1. 0
                            JürgenB
                            1. 0
                              Raketenwissenschaftler
                              1. 0
                                Raketenbastler
                2. 0
                  Gunnar Bittersmann
          2. 0
            Raketeningrid
            1. 0
              Rolf B
              1. 0
                Raketenwissenschaftler
    3. 0
      MudGuard
      1. 0
        JürgenB
  4. 0
    JürgenB

Hallo,

mit folgendem Ausdruck

var tval = val.replace(/\s| | |\u00A0| |\u202f| | |\u2009|´|'|\./g,"");

entferne ich alle mir bekannten Tausendertrennzeichen aus einer Zahl. Jetzt habe ich mal einen Blick in die Doku geworfen und gelesen, das \s schon alle Arten von Worttrennzeichen erfasst. Daher sollte

var tval = val.replace(/\s|´|'|\./g,"");

reichen. Habe ich da die Doku richtig verstanden, oder entgeht mir da noch irgendein Leerzeichen?

Gruß
Jürgen

  1. Hallo!

    mit folgendem Ausdruck

    var tval = val.replace(/\s| | |\u00A0| |\u202f| | |\u2009|´|'|\./g,"");
    

    entferne ich alle mir bekannten Tausendertrennzeichen aus einer Zahl. Jetzt habe ich mal einen Blick in die Doku geworfen und gelesen, das \s schon alle Arten von Worttrennzeichen erfasst.

    Das ist richtig. Siehe MDN.

    Daher sollte

    var tval = val.replace(/\s|´|'|\./g,"");
    

    reichen.

    Ja. Allerdings macht es etwas anders als dein Code oben. Der Code oben geht davon aus, daß "val" ein String mit HTML ist, das Zeichenreferenzen enthalten kann. Du entfernst teilweise die Zeichenreferenzen, teilweise die Unicode-Zeichen direkt.

    Wenn du nur \s verwenden willst, dann müsstest du dafür sorgen, dass vorher alle Zeichenreferenzen zu Zeichen umgewandelt werden. D.h. du operierst dann auf Plain Text und nicht mehr auf HTML. Das wäre der einfachste Weg.

    Wenn auf HTML-Code operieren musst und Zeichenreferenzen auch berücksichtigen willst, müsstest du streng genommen alle Varianten unterstützen: benannt, numerisch dezimal, numerisch hexadezimal. Außerdem lässt sich ein Zeichen numerisch unterschiedlich ausdrücken. Beispielsweise ist   gleichwertig mit  . Da kommst du in Gefilde, die sich mit Regulären Ausdrücken schwer abdecken lassen. Diese Erkennung sollte ein HTML-Parser übernehmen.

    Peter

    1. Hallo Peter,

      … Der Code oben geht davon aus, daß "val" ein String mit HTML ist, das Zeichenreferenzen enthalten kann. Du entfernst teilweise die Zeichenreferenzen, teilweise die Unicode-Zeichen direkt.

      das kam in einer älteren Version per innerHTML aus einem html-Element. Inzwischen nehme ich textContent.

      Gruß
      Jürgen

  2. Hallo JürgenB,

    was willst Du denn da ersetzen? Die Zeichenfolge   - oder das Zeichen mit dem Zeichencode 160?

    In HTML wird   nämlich ersetzt, also z.B.

    <button type="button"
            onclick='alert("Yo <\u00a0> <&#160;>")'>
    Click Me
    </button>
    

    würde Yo < > < > anzeigen.

    Wohingegen

    <button type="button" onclick='foo()'>Gucky!</button>
    
    <script>
    function foo() {
       alert("Hey <\u00a0> <&#160;>");
    }
    </script>
    

    zur Ausgabe von Hey < > <&#160;> führt.

    D.h. deine ursprüngliche Regex matcht diverse Space-Varianten und ihre HTML Symbole. \s wird aber sicherlich nicht die HTML Symbole matchen, sondern nur die Unicode-Zeichen.

    Rolf

    --
    sumpsi - posui - obstruxi
    1. Hallo Rolf,

      eigentlich will ich nur Tausendertrennzeichen aus einem td entfernen. Der Regex stammt noch aus der Zeit, als ich die Tabellenzelle mit innerHTML ausgelesen habe. Ich habe da einfach alles reingepackt, was mir so eingefallen ist. Inzwischen nehme ich textContent, habe den Regex aber noch nicht wieder angefasst.

      Gruß
      Jürgen

  3. var tval = val.replace(/\s|&nbsp;|&#160;|\u00A0|&#8239;|\u202f|&thinsp;|&#8201;|\u2009|´|'|\./g,"");
    

    entferne ich alle mir bekannten Tausendertrennzeichen aus einer Zahl.

    Hm. jetzt hatte ich doch geglaubt, das Problem sei gelöst… und sehe irre kompliziertes Zeug.

    Zuerst wäre da die Frage, wo denn die "Zahl" (es ist ein String) herkommt?

    Dann scheint die Frage auf, warum Du nicht ganz stumpf mit

    var dec = str.replace( /[^0-9.]/g, '' );
    

    alle Zeichen rausziehst, die Du in einer "Zahl" nicht erwartest. Wenn da Oktal- oder Hexadezimalmüll drin steht, dann hat sich womöglich jemand bei der Eingabe ganz gewaltig vertan. Auch hab ich noch nie eine Oktal- oder Hexadezimalzahl mit Kommastellen oder Tausendertrennzeichen gesehen…

    Kommen die „Strings mit vermuteten Zahlenangaben“ etwa via Request von fremden Webseiten?

    Dann sieh Dir mal das hier an:

    
    function mkCleanNumber( s ) {
    	return s.replace( /&#.*;/g, '' ).replace( /[^0-9.]/g, '' );
    }
    
    str='123\u00A0456';
    console.log( str + ' : ' + mkCleanNumber( str ) );
    
    str='123&thinsp;456'
    console.log( str + ' : ' + mkCleanNumber( str ) );
    
    str='123&#8201;456';
    console.log( str + ' : ' + mkCleanNumber( str ) );
    

    Ausgaben:

    123 456 : 123456
    123&thinsp;456 : 123456
    123&#8201;456 : 123456
    
    1. Hallo,

      die Zahlen werden mit textContent aus einer HTML-Tabelle ausgelesen, liegen also als String vor. Da das Script frei verwendet werden kann, habe ich natürlich keinen Einfluss auf das, was der Seitenautor da reinschreibt. Ich will es den Anwendern des Scripts nur so einfach wie möglich machen.

      Ich überarbeite gerade das Script im Tutorial https://wiki.selfhtml.org/wiki/JavaScript/Tutorials/Tabellen_dynamisch_sortieren.

      Da in der Tabellenzelle nicht zwingend Zahlen stehen, kann ich auch nicht alles, was keine Ziffer ist, entfernen. Ich entferne daher die mir bekannten Tausendertrennzeichen, passe bei Bedarf das Dezimalzeichen noch an, und prüfe dann mit isNaN auf Zahl.

      Die Suche nach den Tausendertrennzeichen möchte ich hier vereinfachen.

      Gruß
      Jürgen

      1. Ich überarbeite gerade das Script im Tutorial https://wiki.selfhtml.org/wiki/JavaScript/Tutorials/Tabellen_dynamisch_sortieren.

        Ich bin mir nicht ganz sicher, ob es wohl richtig sein kann, in einem Tutorial, welches sich um das Sortieren von Tabellen dreht, komplizierte reguläre Ausdrücke zu verwenden um auf eine möglichst universelle Weise (diese typisch deutschen Ingenieure wieder…) aus Strings mit Tausendertrennzeichen Zahlen zu machen.

        Ich bin mir aber fast sicher, dass das geschätzte 90% der Leser überfordert. Anders ausgedrückt, halte ich es für „wahrscheinlich besser“, das Tausendertrennzeichen (so man sich überhaupt an der Stelle darum kümmert) konkret angeben zu lassen (Das wird wohl in den meisten Fällen bekannt sein) und für alles weitere auf einen speziellen Artikel zu verweisen.

        1. Hallo,

          Ich bin mir aber fast sicher, dass das geschätzte 90% der Leser überfordert. Anders ausgedrückt, halte ich es für „wahrscheinlich besser“, das Tausendertrennzeichen (so man sich überhaupt an der Stelle darum kümmert) konkret angeben zu lassen (Das wird wohl in den meisten Fällen bekannt sein) und für alles weitere auf einen speziellen Artikel zu verweisen.

          ich biete eine etwas umfangreichere Version des Tabellensortierers ja noch auf meiner Seite an. Die meisten Rückfragen kommen wegen „falsch“ sortierter Zahlen.

          Natürlich soll ein Tutorial so einfach wie möglich sein, daher möchte ich ja den umfangreichgen Regex durch etwas einfaches ersetzen.

          var tval = val.replace(/\s|´|'|\./g,"");
          

          ist mMn für das Tutorial noch nicht zu kompliziert. Wobei ich momentan dazu tendiere, die schweizerischen Trennzeichen wegzulassen.

          Und meine Frage war ja auch nur: findet \s alle als Tausendertrennzeichen verwendeten Leerzeichen.

          Gruß
          Jürgen

          1. var tval = val.replace(/\s|´|'|\./g,"");
            

            ist mMn für das Tutorial noch nicht zu kompliziert.

            Das mag sein. Aber ich vermute eben, dass auch das schon für sehr viele Leser eines Tutorials nur mit Kopschmerztabletten genießbar ist.

            Ich bin seit 20 Jahren als IT-Trainer für Erwachsene tätig und weiß also aus eigener Erfahrung, was passieren kann.

          2. Hallo Jürgen,

            in die Überlegung, ob das nun fürs Tutorial zu kompliziert ist, will ich mich gar nicht so tief einmischen - ich halte es auch für legitim, für "komplizierte" Teilprobleme in einem Tutorial einfach eine Lösung aus dem Hut zu zaubern ("Wir machen das mal so:") und für die, die's wirklich interessiert, einen weiterführenden Link anzubieten.

            Und meine Frage war ja auch nur: findet \s alle als Tausendertrennzeichen verwendeten Leerzeichen.

            Die viel spannendere Frage, die bei der Interpretation von Zahlen immer wieder auftritt: Wonach entscheidest du, was ein Tausender-Trennzeichen ist (Komma oder Punkt), und was ein Dezimaltrennzeichen (Punkt oder Komma)?
            Das Thema wurde hier in letzter Zeit schon öfter angesprochen, und jedesmal war das Fazit: Egal wie man's macht, es wird immer Fälle geben, wo die Interpretation zielsicher falsch liegt.

            Live long and pros healthy,
             Martin

            --
            Ich stamme aus Ironien, einem Land am sarkastischen Ozean.
            1. Hallo Martin,

              Die viel spannendere Frage, die bei der Interpretation von Zahlen immer wieder auftritt: Wonach entscheidest du, was ein Tausender-Trennzeichen ist (Komma oder Punkt), und was ein Dezimaltrennzeichen (Punkt oder Komma)?
              Das Thema wurde hier in letzter Zeit schon öfter angesprochen, und jedesmal war das Fazit: Egal wie man's macht, es wird immer Fälle geben, wo die Interpretation zielsicher falsch liegt.

              das ist die andere Baustelle. Meine Idee ist, das über das lang-Attribut von der Tabelle oder vom Dokument zu regeln. Aber da tun sich schon die ersten Probleme auf: In Spanien nimmt man das Dezimalkomma, in Costa Rica aber den Punkt. Die Abfrage auf „es“ bringt da nichts. In der jetzigen Testversion prüfe ich nur auf „de“. Darüber werden die Hilfetexte in deutsch oder englisch angeboten.

              Eine andere Idee ist, die Zahleninterpretation nicht über das lang-Attribut zu steuern, sondern über das class-Attribut (z.B. class = "dezimalpunkt") oder ein data-Attribut.

              Gruß
              Jürgen

              1. @@JürgenB

                In Spanien nimmt man das Dezimalkomma, in Costa Rica aber den Punkt. Die Abfrage auf „es“ bringt da nichts.

                Es gibt Region-Subtags.

                🖖 Stay hard! Stay hungry! Stay alive! Stay home!

                --
                Home Office ist so frustierend, weil man jetzt noch viel stärker bemerkt mit wievielen Menschen man zu tun hat, die nicht sinnerfassend lesen können. (@Grantscheam)
                1. Hallo Gunnar,

                  In Spanien nimmt man das Dezimalkomma, in Costa Rica aber den Punkt. Die Abfrage auf „es“ bringt da nichts.

                  Es gibt Region-Subtags.

                  ich weiß. „es-cr“ oder so wäre hier die Lösung. Meine Idee war, auf Basis dieser Seite über das lang-Attribut zu entscheiden, ob es um Punkt oder Komma geht, aber schon beim vierten Land hat eine Sprachprüfung nicht gereicht.

                  Gruß
                  Jürgen

          3. @@JürgenB

            ist mMn für das Tutorial noch nicht zu kompliziert.

            Ob kompliziert oder nicht, das hat in diesem Tutorial einfach nichts zu suchen, IMHO.

            Ein Tutorial sollte alles Nötige behandeln, was zum Thema des Tutorials gehört. Nicht weniger, aber auch nicht mehr.

            Gehört die Behandlung von Tausendertrennzeichen zur Sortierung von Tabellendaten? Wohl nicht. Also raus damit, das ist Stoff für ein anderes Tutorial – auf das du dann verlinken kannst.

            🖖 Stay hard! Stay hungry! Stay alive! Stay home!

            --
            Home Office ist so frustierend, weil man jetzt noch viel stärker bemerkt mit wievielen Menschen man zu tun hat, die nicht sinnerfassend lesen können. (@Grantscheam)
            1. Hallo Gunnar Bittersmann,

              ist mMn für das Tutorial noch nicht zu kompliziert.

              Ob kompliziert oder nicht, das hat in diesem Tutorial einfach nichts zu suchen, IMHO.

              Wenn du das Tutorial gelesen hättest, wüsstest du, dass dies Problematik keinesfalls thematisiert wird.

              Gehört die Behandlung von Tausendertrennzeichen zur Sortierung von Tabellendaten? Wohl nicht. Also raus damit, das ist Stoff für ein anderes Tutorial – auf das du dann verlinken kannst.

              Die Behandlung von Tausendertrennzeichen ist Bestandteil des Skriptes. Mich ärgert, dass das hier in diese Richtung abdriftet.

              Bis demnächst
              Matthias

              --
              Du kannst das Projekt SELFHTML unterstützen,
              indem du bei Amazon-Einkäufen Amazon smile (Was ist das?) nutzt.
              1. @@Matthias Apsel

                Wenn du das Tutorial gelesen hättest, wüsstest du, dass dies Problematik keinesfalls thematisiert wird.

                Die Behandlung von Tausendertrennzeichen ist Bestandteil des Skriptes.

                Eben da stellt sich die Frage: Sollte die Behandlung von Tausendertrennzeichen Bestandteil des Scriptes sein, in welchem es um Tabellensortierung geht?

                Mich ärgert, dass das hier in diese Richtung abdriftet.

                Watt mutt, datt mutt.

                🖖 Stay hard! Stay hungry! Stay alive! Stay home!

                --
                Home Office ist so frustierend, weil man jetzt noch viel stärker bemerkt mit wievielen Menschen man zu tun hat, die nicht sinnerfassend lesen können. (@Grantscheam)
                1. Hallo Gunnar,

                  Eben da stellt sich die Frage: Sollte die Behandlung von Tausendertrennzeichen Bestandteil des Scriptes sein, in welchem es um Tabellensortierung geht?

                  ntürlich. Ein Tabellensortierer muss auch nach Zahlen sortieren können. Da das schmale geschützte Leerzeichen auf keiner Tastatur vorhanden ist, und vom Safari auch nur sehr schmal (Breite 0) dargestellt wird, muss man auch andere Leerzeichen berücksichtigen. Die Behandlung ist dann einfach, einfach weg damit. Ein größeres Problem sind Punkt und Komma, die sowohl Tausender- als auch Dezimalzeichen sein können.

                  Gruß
                  Jürgen

                  1. @@JürgenB

                    Ein Tabellensortierer muss auch nach Zahlen sortieren können.

                    Ja. Ein einfacher Tabellensortierer muss Zahlen ohne Tausendertrennzeichen sortieren können. Das sollte für dieses Tutorial genügen. Tutorials sollten nicht zu große, aber in sich abgeschlossene Häppchen sein.

                    Am Ende kann man als Ausblick andeuten, was zu tun wäre, um den einfachen Tabellensortierer um die Behandlung von Tausendertrennzeichen zu erweitern; ggfs. auf ein ergänzendes Tutorial verlinken.

                    🖖 Stay hard! Stay hungry! Stay alive! Stay home!

                    --
                    Home Office ist so frustierend, weil man jetzt noch viel stärker bemerkt mit wievielen Menschen man zu tun hat, die nicht sinnerfassend lesen können. (@Grantscheam)
                    1. Hallo Gunnar,

                      und du meinst, ein var tval = val.replace(/\s/g,""); ist da schon zu kompliziert und sollte ausgelagert werden? Ich würde die Zahlenbehandlung sonst in ein Unterkapitel legen.

                      Gruß
                      Jürgen

                      1. @@JürgenB

                        und du meinst, ein var tval = val.replace(/\s/g,""); ist da schon zu kompliziert und sollte ausgelagert werden?

                        Wenn’s denn dieser Einzeiler ist, kann er auch drinbleiben und in einem Satz erklärt werden. Vielleicht auch erwähnen, warum man nur Leerzeichen behandelt, nicht Punkt und Komma …

                        Das wäre ein Fass ohne Boden. Was dem einen sein Tausendertrennzeichen, ist dem anderen sein Dezimaltrennzeichen.


                        Vielleicht kamm man aber auch einen anderen Weg gehen. Die Zahlen kommen doch aus einer Quelle, wo sie nicht regional formatiert vorliegen? Die könnte man also unterbringen und müsste nicht die regional formatierte Form zurückkonvertieren:

                        <span data-value="9876.50">9.876,50</span>
                        

                        Bei vorhandenem data-value-Attribut nimmt der Tabellensortierer dessen Wert, nicht den Elementinhalt.

                        Was sagen eigentlich Screenreader zu Tausendertrennzeichen? Womöglich braucht man’s sogar so:

                        <span data-value="9876.50">
                          <span aria-hidden="true">9.876,50</span>
                          <span class="visually-hidden">9876,50</span>
                        </span>
                        

                        🖖 Stay hard! Stay hungry! Stay alive! Stay home!

                        --
                        Home Office ist so frustierend, weil man jetzt noch viel stärker bemerkt mit wievielen Menschen man zu tun hat, die nicht sinnerfassend lesen können. (@Grantscheam)
                        1. Hallo Gunnar,

                          und du meinst, ein var tval = val.replace(/\s/g,""); ist da schon zu kompliziert und sollte ausgelagert werden?

                          Wenn’s denn dieser Einzeiler ist, kann er auch drinbleiben und in einem Satz erklärt werden. Vielleicht auch erwähnen, warum man nur Leerzeichen behandelt, nicht Punkt und Komma …

                          Das wäre ein Fass ohne Boden. Was dem einen sein Tausendertrennzeichen, ist dem anderen sein Dezimaltrennzeichen.

                          ich glaube, die Internationalisierung lasse ich im Wiki lieber weg. Ich lasse es, wie es ist und vereinfache nur den Regex.

                          Vielleicht kamm man aber auch einen anderen Weg gehen. Die Zahlen kommen doch aus einer Quelle, wo sie nicht regional formatiert vorliegen? Die könnte man also unterbringen und müsste nicht die regional formatierte Form zurückkonvertieren:

                          <span data-value="9876.50">9.876,50</span>
                          

                          Bei vorhandenem data-value-Attribut nimmt der Tabellensortierer dessen Wert, nicht den Elementinhalt.

                          in meiner umfangreicheren Version ist das schon drin.

                          Was sagen eigentlich Screenreader zu Tausendertrennzeichen? Womöglich braucht man’s sogar so:

                          <span data-value="9876.50">
                            <span aria-hidden="true">9.876,50</span>
                            <span class="visually-hidden">9876,50</span>
                          </span>
                          

                          ich vermute mal, das viele Anwender meines Tabellensortierers mit dem Thema A11Y noch nie zu tun hatten. Und da ich den Sortierer, nicht aber die Tabellen liefere, habe ich darauf auch keinen Einfluss. Wenn aber jemand mit so einer Tabelle käme, würde ich wahrscheinlich sogar eine Einzellösung basteln. Wenn aber das äußere span ein td ist, funktioniert es jetzt schon, nur das ich statt data-value ein data-sort_key erwarte.

                          Gruß
                          Jürgen

                        2. Hallo Gunnar,

                          jetzt bringst Du ein „Fremdthema“ in die Diskussion: Accessibility.

                          Ein einfacher Tabellensortierer sollte allein mit parseFloat(input, replace(",", ".")) auskommen. Komma durch Punkt ersetzen hilft bei deutscher Darstellung, und parseFloat beinhaltet ein trim. trim entfernt schon eine MENGE Zeichen aus dem String: \x20, \xa0, \u2002 bis \u200a, \u202f, \u205f, \u3000 und \ufeff. Das muss reichen.

                          Was darüber hinausgeht ist Kür, nicht Pflicht. Tausendertrennzeichen und andere Sondernzeichen innerhalb der Zahl, Währungssymbole, HTML Symbole für spezielle Zeichen, Zeichenformatierung, Darstellung negativer Zahlen durch rote Farbe oder Klammern, Aufbereiten dieses Durcheinanders für Screenreader - das gehört in ein Tutorial über Tabellensortieren nur insofern 'rein, als dass man es explizit als "Out Of Scope" und "Here Be Dragons" aufführt.

                          Rolf

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

                            jetzt bringst Du ein „Fremdthema“ in die Diskussion: Accessibility.

                            Nein. Accessibility ist kein Fremdthema, sondern immer mit dabei. Kein Tutorial sollte Beispiele bringen, die nicht benutzbar sind.

                            Und mit benutzbar meine ich: benutzbar; nicht: für einige benutzbar.

                            Das gesagt, auch wenn sowas wie aria-hidden="true" in einem Beispiel auftaucht, ist es außerhalb des Scopes, das in einem solchen Tutorial zu erklären.

                            Und es war auch nur so eine Idee. Womöglich ist das gar nicht nötig. Zahlen mit Tausendertrennzeichen kommen ja desöfteren auf Webseiten vor. Entweder Screenreader wissen damit umzugehen oder Screenreader-Nutzer sind es gewöhnt, solche Zahlen etwas komisch vorgelesen zu bekommen.

                            🖖 Stay hard! Stay hungry! Stay alive! Stay home!

                            --
                            Home Office ist so frustierend, weil man jetzt noch viel stärker bemerkt mit wievielen Menschen man zu tun hat, die nicht sinnerfassend lesen können. (@Grantscheam)
                            1. Hallo Gunnar,

                              Accessibility ist (...) immer mit dabei.

                              Jaaaa (Becker-Faust) - ich hab den Trigger erwischt 😂. A11Y ist genauso immer mit dabei wie die HTTP-Spec, es funktioniert nicht ohne, aber man muss nicht immer drauf rumreiten.

                              Kein Tutorial sollte Beispiele bringen, die nicht benutzbar sind.

                              Ja. Eben. Deswegen ja auch die Anregung von mir, jegliche spezielle Formatierung auszuklammern. In dem Fall brauchst Du keine Maßnahmen, die A11Y gewährleisten, und kannst Erläuterungen dazu aus dem Tutorial heraushalten.

                              Rolf

                              --
                              sumpsi - posui - obstruxi
                          2. Hallo Rolf,

                            parseFloat war zu großzügig bei der Umwandlung von Strings in Zahlen, daher prüfe ich lieber mit isNaN.

                            A11Y ist im Tutorial schon ein Thema, da ja die Spaltenüberschriften in Buttons umgewandelt werden müssen.

                            Gruß
                            Jürgen

    2. str='123\u00A0456\u00A0789.123';
      console.log( str + ' : ' + mkCleanNumber( str ) );
      str='123&thinsp;456&thinsp;789.123'
      console.log( str + ' : ' + mkCleanNumber( str ) );
      str='123&#8201;456&#8201;789.123';
      console.log( str + ' : ' + mkCleanNumber( str ) );
      
      function mkCleanNumber( s ) {
      	return parseFloat( 
      		s.replace( /&#[0-9a-fx]*;/ig, '' ).replace( /[^0-9.]/g, '' )
      	);
      }
      
      function mkCleanNumber( s ) {
      	return parseFloat( 
      		s.replace( /&#[0-9a-fx]*;/ig, '' ).replace( /[^0-9.]/g, '' )
      	);
      }
      
      

      Ausgaben:

      123 456 789.123               : 123456789.123
      123&thinsp;456&thinsp;789.123 : 123456789.123
      123&#8201;456&#8201;789.123   : 123456789.123
      
      1. Als ich die Angabe des Dezimalseperators (Komma) berücksichtigen wollte ist mir aufgefallen, dass der Regex zu oft kompiliert wird. Das könnte bei großen Tabellen und langsamen Endgeräten ins Gewicht fallen.

        Ergo hab ich das Zeug mal in eine Klasse gepackt, dann geschieht (nicht nur das, sondern auch die Kompilierung der je nach Dezimalseperator unterschiedlichen Methoden) nur einmal. Außerdem hab ich noch eine Prüfung vorgesehen, nämlich für den Fall, dass eine echte Zahl übergeben wird.

        class toCleanNumber {
        	constructor( decSep = '.' ) {
        		this.search_1 = new RegExp( '&[^;]+;', 'ig' );
        		this.search_2 = new RegExp( '[^0-9' + decSep + ']' , 'g' );
        		this.decSep = decSep;
        		if ( '.' != this.decSep ) {
        			this.getFloat = function ( s ) {
        				if ( isNaN( s ) ) {
        					return parseFloat(s.replace( this.search_1, '' ).replace( this.search_2, '' ).replace( this.decSep, '.' ) );
        				} else {
        					return s;
        				}
        			}		
        		} else {
        			this.getFloat = function ( s ) {
        				if ( isNaN( s ) ) {
        					return parseFloat( s.replace( this.search_1, '' ).replace( this.search_2, '' ) );
        				} else {
        					return s;
        				}
        			}
        		}
        	}
        }
        
        ////////////////////////////////
        //
        // Test für "Zahlen" mit Komma:
        //
        ////////////////////////////////
        
        cleaner = new toCleanNumber( ',' );
        
        i = 123456789;
        console.log( i + ' : ' + cleaner.getFloat( i ) );
        console.log();
        
        str = '123\u00A0456\u00A0789,123    ';
        console.log( str + ' : ' + cleaner.getFloat( str ) );
        console.log();
        
        str = '123&thinsp;456&thinsp;789,123';
        console.log( str + ' : ' + cleaner.getFloat( str ) );
        console.log();
        
        str = '123&#8201;456&#8201;789,123  ';
        console.log( str + ' : ' + cleaner.getFloat( str ) );
        console.log();
        
        ////////////////////////////////
        //
        // Test für "Zahlen" mit Punkt:
        //
        ////////////////////////////////
        
        cleaner = new toCleanNumber();
        
        i = 123456789;
        console.log( i + ' : ' + cleaner.getFloat( i ) );
        console.log();
        
        str = '123\u00A0456\u00A0789.123   ';
        console.log( str + ' : ' + cleaner.getFloat( str ) );
        console.log();
        
        str = '123&thinsp;456&thinsp;789.123';
        console.log( str + ' : ' + cleaner.getFloat( str ) );
        console.log();
        
        str = '123&#8201;456&#8201;789.123  ';
        console.log( str + ' : ' + cleaner.getFloat( str ) );
        console.log();
        
        1. Hallo Raketeningrid,

          da hätte ich Hinweise.

          (1) die this.* Zuweisungen können genauso gut lokale Variablen sein, die sind als Closure in der getFloat-Implementierung verfügbar
          (2) if ( isNaN( s ) ) { - da fehlt ein ! (not), oder?
          (3) Den decSep musst Du beim Aufbau der search_2 Regex escapen. Es könnte ein ] sein (jaa, ok, ist an meinen letzten Haaren herbeigezogen) (3) Default-Argumente gibt's nicht im IE, da ist das ein Syntaxfehler.

          Und eine Frage:

          Ist es wirklich gut, jede &#-Sequenz zu plätten? Ich denke dabei an &#30; oder &#2E;…

          Rolf

          1. @@Rolf B

            Ist es wirklich gut, jede &#-Sequenz zu plätten? Ich denke dabei an &#30; oder &#2E;…

            Wozu soll das überhaupt gut sein? Zeichenreferenzen kommen doch im Inhalt gar nicht vor? Die hat der Browser doch längst aufgelöst, bevor JavaScript losackert?

            <p lang="de">unzertrennliche&nbsp;Freunde</p>
            
            const textContent = document.querySelector('p').textContent;
            
            console.log(textContent.indexOf('&')); // -1
            console.log(textContent.indexOf('\u{00A0}')); // 15
            

            (Codepen)

            🖖 Stay hard! Stay hungry! Stay alive! Stay home!

            --
            Home Office ist so frustierend, weil man jetzt noch viel stärker bemerkt mit wievielen Menschen man zu tun hat, die nicht sinnerfassend lesen können. (@Grantscheam)
            1. Hm. Ich hab das genommen, was der TO vorgab...

              Zu Deinem Test:

              const textContent = document.querySelector('p').textContent;
              
              console.log(textContent.indexOf('&')); // -1
              console.log(textContent.indexOf('\u{00A0}')); // 15
              

              Invertiertes Ergebnis:

              const textContent = document.querySelector('p').innerHTML;
              
              console.log(textContent.indexOf('&')); // 15
              console.log(textContent.indexOf('\u{00A0}')); // -1
              

              Da muss man wohl sehr aufpassen, wie man die vermeintlichen Zahlen gewinnt.

              1. @@Raketeningrid

                const textContent = document.querySelector('p').innerHTML;
                
                console.log(textContent.indexOf('&')); // 15
                console.log(textContent.indexOf('\u{00A0}')); // -1
                

                Da muss man wohl sehr aufpassen, wie man die vermeintlichen Zahlen gewinnt.

                Guter Hinweis. Und zwar sehr dolle:

                <p lang="de">unzertrennliche&#x00A0;Freunde</p>
                
                const textContent = document.querySelector('p').innerHTML;
                
                console.log(textContent.indexOf('&#x00A0;')); // -1
                console.log(textContent.indexOf('&nbsp;')); // 15
                

                (Codepen)

                Im Quelltext steht eine numerische Zeichenreferenz; in innerHTML aber nicht.


                innerText verhält sich hier wie textContent.

                🖖 Stay hard! Stay hungry! Stay alive! Stay home!

                --
                Home Office ist so frustierend, weil man jetzt noch viel stärker bemerkt mit wievielen Menschen man zu tun hat, die nicht sinnerfassend lesen können. (@Grantscheam)
                1. Hallo,

                  in meinem Test findet \s in dieser mit textContent ausgelesenen Zeile alle Trennzeichen:

                  <td>1&nbsp;000&thinsp;000&#8239;000&#8201;000&#x202f;000&#x00A0;000&#x2009;000&#160;000</td>
                  

                  Gruß
                  Jürgen

                  1. in meinem Test findet \s in dieser mit textContent ausgelesenen Zeile alle Trennzeichen:

                    Naja. Ich hab mich drauf verlegt, ALLES zu eliminieren, was weder Ziffer noch Komma ist bzw. repräsentiert. Entities können Ziffern enthalten, deswegen: "Hinfort damit!"

                    1. Verständnisfrage allgeimein: ich kann der ganzem Nummer nicht folgen. Jeglicher Normalisierungsprozess sollte doch serverseitig passieren. Warum nun das ganze JavaScript-Geraffel? Dann auch noch bei einem Tutorial für einen JS-Tabellensorter?

                      Nix verstehen.

                      1. Hallo,

                        Verständnisfrage allgeimein: ich kann der ganzem Nummer nicht folgen. Jeglicher Normalisierungsprozess sollte doch serverseitig passieren. Warum nun das ganze JavaScript-Geraffel? Dann auch noch bei einem Tutorial für einen JS-Tabellensorter?

                        Der Tabellensortierer läuft Clientseitig und muss als Daten nehmen, was in der Tabelle steht. Wenn da „1234.567“ steht, ist alles ok, wenn da aber „1 234,567“ steht, fangen die Probleme an: ich bekomme Mails mit dem „Vorwurf“: der Sortierer sortiert falsch.

                        Daher habe ich auch in das Sortierer-Tutorial eine kleine „Zahleninterpretation“ eingebaut. Da der hierfür verwendete Reguläre Ausdruck aus meiner Sicht zu kompliziert und auch „doppelt gemoppelt“ war, wollte ich ihn vereinfachen, was wohl auch geht.

                        Gruß
                        Jürgen

                        1. Glaube schon, euch inhaltlich halbwegs folgen zu können, aber das Argument „ich bekomme Mails mit dem Vorwurf: der Sortierer sortiert falsch“ zieht für mich nicht.

                          Die Problematik kann man durchaus mit einem Satz anreißen und die Lösungsansätze (für ein durchaus komplexes! Problem) auf einen anderen Wiki-Eintrag verlinken.

                          Fertig! KISS ;-)

                          1. Hallo,

                            ich glaube

                            var tval = val.replace(/\s/g,"").replace(",", ".");
                            

                            ist simpel genug.

                            Gruß
                            Jürgen

                            1. Ja. Mach das so.

                              „Weniger ist manchmal mehr“ - und Du hast einen schönen Anker um zu vermerken, dass der Anwender selbst was tun muss, wenn seine "Zahlen" auf unvorhersehbare Weise formatiert sind.

                              1. Ich hatte, dank der, auch in der Erwachsenenausbildung stattfindenden „Coronaferien“ gerade ein wenig Zeit um damit herumzuspielen… und also dem Skript einen (hoffentlich) letzten Schliff gegeben und die Tests ausgeweitet.

                                // toCleanNumber.js
                                class toCleanNumber {
                                
                                	constructor( decSep = '.' ) {
                                        this.setNewDecSep( decSep );
                                	}
                                	
                                	setNewDecSep ( decSep ) {
                                		if ( this.decSep != decSep ) {
                                			this.search_1 = new RegExp( '&[^;]+;', 'g' );
                                			this.search_2 = new RegExp( '[^0-9' + decSep + ']' , 'g' );
                                			this.decSep = decSep;
                                		}
                                		if ( '.' != this.decSep ) {
                                			this.getFloat = function ( s ) {
                                				if ( isNaN( s ) ) {
                                					return parseFloat(s.replace( this.search_1, '' ).replace( this.search_2, '' ).replace( this.decSep, '.' ) );
                                				} else {
                                					return parseFloat( s );
                                				}
                                			}		
                                		} else {
                                			this.getFloat = function ( s ) {
                                				if ( isNaN( s ) ) {
                                					return parseFloat( s.replace( this.search_1, '' ).replace( this.search_2, '' ) );
                                				} else {
                                					return parseFloat( s );
                                				}
                                			}
                                		}
                                	}
                                }
                                
                                
                                /////////////////////////////////////////
                                //
                                // Tests: Für Produktivbetrieb entfernen
                                //
                                /////////////////////////////////////////
                                
                                //toCleanNumberTest1();
                                //toCleanNumberTest2();
                                
                                //// toCleanNumberTest3( decSep=',', tSep='.', show=false );
                                //toCleanNumberTest3( '.', ' ', true );
                                //toCleanNumberTest3( ',', ' ', true );
                                //toCleanNumberTest3( '.', ' ', false );
                                //toCleanNumberTest3( ',', ' ', false );
                                toCleanNumberTest3( ',', '&nbsp;', false );
                                toCleanNumberTest3( '.', ' ', false );
                                toCleanNumberTest4( ' ', false );
                                
                                function toCleanNumberTest1() {
                                
                                	////////////////////////////////
                                	//
                                	// Test für "Zahlen" mit Komma:
                                	//
                                	////////////////////////////////
                                
                                	cleaner = new toCleanNumber(',');
                                	//cleaner.setNewDecSep( ',' );
                                
                                	s = 123456789;
                                	i = cleaner.getFloat( s );
                                	console.log( s + ' : ' + i + ' : ' + typeof( i ) );
                                
                                	s = '123\u00A0456\u00A0789,123';
                                	i = cleaner.getFloat( s );
                                	console.log( s + ' : ' + i + ' : ' + typeof( i ) );
                                
                                	s = '123&thinsp;456&thinsp;789,123';
                                	i = cleaner.getFloat( s );
                                	console.log( s + ' : ' + i + ' : ' + typeof( i ) );
                                
                                	s = '123&#8201;456&#8201;789,123  ';
                                	i = cleaner.getFloat( s );
                                	console.log( s + ' : ' + i + ' : ' + typeof( i ) );
                                	console.log();
                                }
                                
                                function toCleanNumberTest2() {
                                
                                ////////////////////////////////
                                //
                                // Test für "Zahlen" mit Punkt:
                                //
                                ////////////////////////////////
                                
                                	cleaner = new toCleanNumber(',');
                                	//cleaner.setNewDecSep( '.' );
                                
                                	s = 123456789;
                                	i = cleaner.getFloat( s);
                                	console.log( s + ' : ' + i + ' : ' + typeof( i ) );
                                
                                	s = '123\u00A0456\u00A0789.123';
                                	i = cleaner.getFloat( s );
                                	console.log( s + ' : ' + i + ' : ' + typeof( i ) );
                                	s = '123&thinsp;456&thinsp;789.123';
                                	i = cleaner.getFloat( s );
                                
                                	s = '123&#8201;456&#8201;789.123  ';
                                	i = cleaner.getFloat( s );
                                	console.log( s + ' : ' + i + ' : ' + typeof( i ) );
                                }
                                
                                ////////////////////////////////
                                //
                                // Stresstest
                                //
                                ////////////////////////////////
                                
                                function toCleanNumberTest3( decSep = ',', tSep   = '.', show=false ) {
                                
                                    Imax   = 10;
                                    Kmax   = 1000;
                                    LMax   = 100;
                                    
                                    arr = new Array();
                                
                                	for ( let i=0; i < Imax; i++ ) {
                                		for ( k=0; k < Kmax; k++ ) {
                                			for ( l=0; l < LMax; l++ ) {
                                				arr.push( '1' + tSep + i.toString() + tSep + k.toString() + decSep + l.toString() );
                                			}
                                		}
                                	}
                                
                                    cleaner = new toCleanNumber( decSep );
                                	startT = Date.now();
                                	
                                	arr.forEach( function( s ) {
                                			z = cleaner.getFloat( s );
                                			if ( show ) {
                                				console.log( s + " : " + z  + ' : ' + typeof( z ) );
                                			}	
                                	} );
                                	
                                	console.log ( 'Mit Klasse/Objekt: ' + ( Imax * Kmax * LMax ).toString()  + ' Strings in ' + ( Date.now() - startT ) + ' Millisekunden konvertiert' );
                                	//console.log ( cleaner.search_1);
                                	//console.log ( cleaner.search_2);
                                }
                                
                                function toCleanNumberTest4( tSep = ' ', show = false ) {
                                	
                                    Imax   = 10;
                                    Kmax   = 1000;
                                    LMax   = 100;
                                    decSep = ','
                                    
                                    arr = new Array();
                                
                                	for ( let i=0; i < Imax; i++ ) {
                                		for ( k=0; k < Kmax; k++ ) {
                                			for ( l=0; l < LMax; l++ ) {
                                				arr.push( i.toString() + tSep + k.toString() + decSep + l.toString() );
                                			}
                                		}
                                	}
                                
                                	startT = Date.now();
                                	
                                	arr.forEach( function( s ) {
                                			z = s.replace(/\s/g,'').replace(',', '.');
                                			
                                			if ( show ) {
                                				console.log( s + " : " + z  + ' : ' + typeof( z ) );
                                			}	
                                	} );
                                	
                                	console.log ( 'Einfaches Replace: ' + ( Imax * Kmax * LMax ).toString()  + ' Strings in ' + ( Date.now() - startT ) + ' Millisekunden konvertiert' );
                                }
                                

                                Wie Du siehts habe ich bei den Tests zum Vergleich auch Deine Lösung (als 'Einfaches Replace') verbaut:

                                Hier die Ergebnisse der Stresstest mit nodejs auf dem Desktop:

                                Mit Klasse/Objekt: 1000000 Strings in 909 Millisekunden konvertiert
                                Mit Klasse/Objekt: 1000000 Strings in 570 Millisekunden konvertiert
                                Einfaches Replace: 1000000 Strings in 328 Millisekunden konvertiert
                                

                                Hier die Ergebnisse der Stresstest mit nodejs auf dem Raspberry Pi 4b+ (hoffentlich vergleichbar mit nicht zu altem Smartphone):

                                Mit Klasse/Objekt: 1000000 Strings in 3092 Millisekunden konvertiert
                                Mit Klasse/Objekt: 1000000 Strings in 1798 Millisekunden konvertiert
                                Einfaches Replace: 1000000 Strings in 824 Millisekunden konvertiert
                                

                                Du kannst also ggf. auf dieses Skript verweisen und den Hinweis geben, dass bei sehr großen Tabellen auf Smartphones, Tabletts oder alten Rechnern durch die notwendige Umrechnung eine spürbare Verlangsamung eintreten kann - wenn die gezeigte und sehr universelle Klasse statt einer individuellen Ersetzung verwendet wird.

                2. @@Gunnar Bittersmann

                  const textContent = document.querySelector('p').innerHTML;
                  

                  Meh. Die Konstante sollte nicht textContent heißen, sondern bspw. innerHTML.

                  🖖 Stay hard! Stay hungry! Stay alive! Stay home!

                  --
                  Home Office ist so frustierend, weil man jetzt noch viel stärker bemerkt mit wievielen Menschen man zu tun hat, die nicht sinnerfassend lesen können. (@Grantscheam)
          2. (2) if ( isNaN( s ) ) { - da fehlt ein ! (not), oder?

            Nö. Wenn nicht eine Zahl übergeben wurde wird die direkt zurück gegeben, sonst wird das als String behandelt… Weitere Prüfungen habe ich wegen der Performance gespart.

            Ist es wirklich gut, jede &#-Sequenz zu plätten? Ich denke dabei an &#30; oder &#2E;…

            Was haben &#30; oder &#2E; (oder ähnliche Sequenzen) in (vermeintlich) Zahlen repräsentierenden Strings zu suchen?

            1. Hallo Raketeningrid,

              oh, autsch. isNaN macht unter der Haube einen parseFloat, wenn es keinen Number-Wert (oder NaN) bekommt? Das muss man erstmal wissen. Ich dachte, du wolltest nur den echten NaN abfangen.

              Aber jetzt wird's konfusionös.

              getFloat("123 345") liefert 123345
              getFloat("123345") liefert "123345"
              getFloat(NaN) stürzt ab

              Den Absturz könnte man als lässlich ansehen, die Quelle ist das DOM und da sollte kein NaN drin stehen. Aber mal einen Number- und mal einen String-Wert. Findest Du das richtig?

              Rolf

              --
              sumpsi - posui - obstruxi
              1. Aber mal einen Number- und mal einen String-Wert.

                Hm. Stimmt. Ich habe nicht bedacht, dass isNaN('123456') eben auch false liefert, weil der String '123456' als Zahl angesehen wird.

                Die beiden Zeilen return s; durch return floatval( s ); zu ersetzen sollte genügen.

    3. Hi,

      alle Zeichen rausziehst, die Du in einer "Zahl" nicht erwartest. Wenn da Oktal- oder Hexadezimalmüll drin steht, dann hat sich womöglich jemand bei der Eingabe ganz gewaltig vertan. Auch hab ich noch nie eine Oktal- oder Hexadezimalzahl mit Kommastellen oder Tausendertrennzeichen gesehen…

      Tausendertrennzeichen nicht, aber es ist durchaus üblich, bei größeren Hexzahlen in Zweier- oder Vierer-Gruppen zu unterteilen.

      A9BC 75DE F123 oder A9 BC 75 DE F1 23 statt A9BC75DEF123

      Vielleicht nicht bei der Eingabe, aber beim Ausdruck schon.

      cu,
      Andreas a/k/a MudGuard

      1. Hallo Andreas,

        A9BC 75DE F123 oder A9 BC 75 DE F1 23 statt A9BC75DEF123

        wenn da als Trennzeichen schmale, normale oder geschützte Leerzeichen verwendet werden, würden die ja wohl mit \s gefunden. Allerdings unterstütze das Script keine Hex-Zahlen.

        Gruß
        Jürgen

  4. Hallo,

    vielen Dank für die vielen Tipps. Damit das Tutorial nicht zu kompliziert wird, werde ich zum Auslesen der Tabellenfelder folgende Funktion verwenden:

    var getData = function (ele, col) {
    	var val = ele.textContent;
    	// Tausendertrenner entfernen, und Komma durch Punkt ersetzen
    	var tval = val.replace(/\s/g,"").replace(",", ".");
    	if (!isNaN(tval) && tval.search(/[0-9]/) != -1) return tval; // Zahl
    	sorttype[col] = "s"; // String
    	return val;
    } // getData
    

    Das funktioniert dann bei Dezimalpunkt und Dezimalkomma. Als Tausendertrenner sind dann nur diverse Leerzeichen erlaubt.

    Auf weitere Internationalisierung werde ich hier verzichten. Es geht im Tutorial ja nicht um den perfekten Tabellensortierer, sondern um das Prinzip.

    Gruß
    Jürgen