Regex - Worttrennzeichen
JürgenB
- javascript
- regex
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
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
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
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> < >")'>
Click Me
</button>
würde Yo < > < >
anzeigen.
Wohingegen
<button type="button" onclick='foo()'>Gucky!</button>
<script>
function foo() {
alert("Hey <\u00a0> < >");
}
</script>
zur Ausgabe von Hey < > < >
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
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
var tval = val.replace(/\s| | |\u00A0| |\u202f| | |\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 456'
console.log( str + ' : ' + mkCleanNumber( str ) );
str='123 456';
console.log( str + ' : ' + mkCleanNumber( str ) );
Ausgaben:
123 456 : 123456
123 456 : 123456
123 456 : 123456
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
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.
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
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.
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
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
@@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!
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
@@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!
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
@@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!
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
@@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!
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
@@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!
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
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
@@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!
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
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
str='123\u00A0456\u00A0789.123';
console.log( str + ' : ' + mkCleanNumber( str ) );
str='123 456 789.123'
console.log( str + ' : ' + mkCleanNumber( str ) );
str='123 456 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 456 789.123 : 123456789.123
123 456 789.123 : 123456789.123
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 456 789,123';
console.log( str + ' : ' + cleaner.getFloat( str ) );
console.log();
str = '123 456 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 456 789.123';
console.log( str + ' : ' + cleaner.getFloat( str ) );
console.log();
str = '123 456 789.123 ';
console.log( str + ' : ' + cleaner.getFloat( str ) );
console.log();
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  oder E;…
Rolf
@@Rolf B
Ist es wirklich gut, jede &#-Sequenz zu plätten? Ich denke dabei an  oder E;…
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 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!
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.
@@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 Freunde</p>
const textContent = document.querySelector('p').innerHTML;
console.log(textContent.indexOf(' ')); // -1
console.log(textContent.indexOf(' ')); // 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!
Hallo,
in meinem Test findet \s
in dieser mit textContent
ausgelesenen Zeile alle Trennzeichen:
<td>1 000 000 000 000 000 000 000 000</td>
Gruß
Jürgen
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!"
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.
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
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 ;-)
Hallo,
ich glaube
var tval = val.replace(/\s/g,"").replace(",", ".");
ist simpel genug.
Gruß
Jürgen
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.
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( ',', ' ', 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 456 789,123';
i = cleaner.getFloat( s );
console.log( s + ' : ' + i + ' : ' + typeof( i ) );
s = '123 456 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 456 789.123';
i = cleaner.getFloat( s );
s = '123 456 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.
@@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!
(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  oder E;…
Was haben  oder E; (oder ähnliche Sequenzen) in (vermeintlich) Zahlen repräsentierenden Strings zu suchen?
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
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.
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
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
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