![]() | |
![]() |
| | Thread Tools | Display Modes |
#1
| |||
| |||
|
#2
| ||||||
| ||||||
|
|
Vielleicht bin ich nicht der einzige, der Strings formatieren, genauer, Platzhalter in Strings durch Variablen ersetzen möchte. |
|
Hier mein Vorschlag, wie man das anstellen kann: String.prototype.format = function() { var args = arguments; return this.replace( /{{.*?}}|{(\d+)(,\s*([\w.]+))?}/g, ^^^^^^^ ^^ ^ |
); um es 100%ig|
function(m, a1, a2, a3) { if (m[1] == '{') return m; |
|
var rpl = args[a1]; if (a3) { var f = eval(a3); ^^^^ |
|
[...] Im einfachsten Fall wird die Funktion einfach so benutzt: alert('Die Temperatur hat heute {0}°C erreicht'.format(35)); |
|
Für unsere Freunde, die es nicht so mit SI-Einheiten haben, ginge es auch so: function CtoF(t) { return (t * 9)/5 + 32; } alert('Today the temperature reached {0,CtoF}°F'.format(35)); |
#3
| |||||||
| |||||||
|
|
Michael Schuerig wrote: Vielleicht bin ich nicht der einzige, der Strings formatieren, genauer, Platzhalter in Strings durch Variablen ersetzen möchte. Du meinst Variablen_werte_. Nein, da haben sich zuvor schon ein paar Leute Gedanken gemacht und z.B. in C geeignete Funktionen geschrieben (*printf*). Eine bislang anscheinend fe lende, allerdings noch nicht 100%ig featuregleiche, ECMAScript-konforme Implementation von printf(3) findest Du seit einiger Zeit hier: http://PointedEars.de/scripts/string.js>, format() |
|
Hier mein Vorschlag, wie man das anstellen kann: String.prototype.format = function() { var args = arguments; return this.replace( /{{.*?}}|{(\d+)(,\s*([\w.]+))?}/g, ^^^^^^^ ^^ ^ Das ist syntaktisch inkorrekt und compiliert daher nicht. `{'...`}' definiert das n-fache Vorkommen des vorhergehenden Ausdrucks (n >= 0). |
|
Es funktioniert aber auch mit korrekter Syntax nicht wie gewünscht, |
|
Konkret matcht die erste Alternative bei korrekter Syntax (d.h. escaped) auch auf {{{x}} |
|
function(m, a1, a2, a3) { if (m[1] == '{') return m; In Deinen Format-Strings darf man also keine geschweiften Klammern benutzen. |
|
var rpl = args[a1]; if (a3) { var f = eval(a3); ^^^^ Lover not, wie der Engländer nie sagen würd'. Überleg mal, was passieren kann, wenn man Deine Methode mit einer Benutzereingabe füttert, beispielsweise "{0,function spamMe() {...}; while (true) {spamMe();};}" |
|
Im einfachsten Fall wird die Funktion einfach so benutzt: alert('Die Temperatur hat heute {0}°C erreicht'.format(35)); Bei meiner Lösung geht's so: alert(format('Die Temperatur hat heute %d°C erreicht', 35)); Für unsere Freunde, die es nicht so mit SI-Einheiten haben, ginge es auch so: function CtoF(t) { return (t * 9)/5 + 32; } alert('Today the temperature reached {0,CtoF}°F'.format(35)); Entsprechend: alert(format('Today the temperature reached %d°F', CtoF(35))); |
#4
| ||||||||||||||
| ||||||||||||||
|
|
Thomas 'PointedEars' Lahn wrote: Michael Schuerig wrote: Vielleicht bin ich nicht der einzige, der Strings formatieren, genauer, Platzhalter in Strings durch Variablen ersetzen möchte. Du meinst Variablen_werte_. Nein, da haben sich zuvor schon ein paar Leute Gedanken gemacht und z.B. in C geeignete Funktionen geschrieben (*printf*). Eine bislang anscheinend fe lende, allerdings noch nicht 100%ig featuregleiche, ECMAScript-konforme Implementation von printf(3) findest Du seit einiger Zeit hier: http://PointedEars.de/scripts/string.js>, format() Printf ist aber nicht das, was ich haben will. Ich brauche die Funktion zum lokalisieren von Strings mit interpolierten (interpositionierten?) |
|
Variablenwerten. Dabei ist es wichtig, dass die Werte in einer anderen Reihenfolge in den Formatstring eingefügt werden können als in ihrer Argumentreihenfolge. |
|
/{{.*?}}|{(\d+)(,\s*([\w.]+))?}/g, ^^^^^^^ ^^ ^ Das ist syntaktisch inkorrekt und compiliert daher nicht. `{'...`}' definiert das n-fache Vorkommen des vorhergehenden Ausdrucks (n >= 0). Danke. Korrigiert. Dummerweise hat es mit einem Browser doch kompiliert. |
|
Es funktioniert aber auch mit korrekter Syntax nicht wie gewünscht, Doch tut es allem Anschein nach. Was aber daran liegt, dass ich wohl etwas anderes wünsche als Du vermutest. Die Funktion muss nicht gegen jeglichen Missbrauch gefeit sein, soll es jemand, der sie verwendet, aber ermöglichen, jeden String zu erzeugen. |
|
Konkret matcht die erste Alternative bei korrekter Syntax (d.h. escaped) auch auf {{{x}} Das stimmt wohl, ist für meinen(!) Anwendungszweck aber nicht ernsthaft relevant. Nach weiterem Überlegen will ich die umschliessenden Klammern ja gar nicht haben. Also return this.replace( /\{\{[^{}]*\}\}|\{(\d+)(,\s*([\w.]+))?\}/g, ^^^^ ^^^^ ^^ ^^ |
|
function(m, a1, a2, a3) { if (m[1] == '{') { ^^^^ return m.slice(1, -1); |
|
function(m, a1, a2, a3) { if (m[1] == '{') return m; In Deinen Format-Strings darf man also keine geschweiften Klammern benutzen. Probier's mal... |
|
Der Test prüft ganz einfach, welche der beiden Alternativen gematcht hat. |
|
var rpl = args[a1]; if (a3) { var f = eval(a3); ^^^^ Lover not, wie der Engländer nie sagen würd'. Überleg mal, was passieren kann, wenn man Deine Methode mit einer Benutzereingabe füttert, beispielsweise "{0,function spamMe() {...}; while (true) {spamMe();};}" Dann war der Benutzer dumm. |
|
Wenn ich schon einen flexible, dynamische Sprache habe, dann nutze ich das auch. |
|
Der Formatstring ist bei meiner Anwendung immer fest vorgegeben, keine Benutzereingabe. |
|
Das ist ein ganz typisches Szenario bei der Lokalisierung von Programmtexten. |
|
function CtoF(t) { return (t * 9)/5 + 32; } alert('Today the temperature reached {0,CtoF}°F'.format(35)); Entsprechend: alert(format('Today the temperature reached %d°F', CtoF(35))); Das würde mir aber überhaupt nicht helfen. |
|
Ich möchte beide Situationen einheitlich behandeln und dazu muss ich an irgendeiner Stelle abstrahieren. |
#5
| ||||||||
| ||||||||
|
|
Michael Schuerig wrote: Printf ist aber nicht das, was ich haben will. Ich brauche die Funktion zum lokalisieren von Strings mit interpolierten (interpositionierten?) `Interpoliert' sicher nicht. MUSEN schon eher das andere. |
|
Danke. Korrigiert. Dummerweise hat es mit einem Browser doch kompiliert. Schlimm. Mit welchem? |
|
return this.replace( /\{\{[^{}]*\}\}|\{(\d+)(,\s*([\w.]+))?\}/g, ^^^^ ^^^^ ^^ ^^ Also??ß |
|
"{0,function spamMe() {...}; while (true) {spamMe();};}" Dann war der Benutzer dumm. Eher schlau. Bedenke, dass *Du* die _Sicherheitslücke_ öffnest. Der Cracker muss sie nur ausnutzen. Deshalb wird das Script mit diesem Ansatz wenig bis keine Verbreitung finden, und einen Programmierer, der es (insbesondere, aber nicht nur, für ein kommerzielles Projekt) unverändert einsetzt, muss man als inkompetent einstufen. |
|
Der Formatstring ist bei meiner Anwendung immer fest vorgegeben, keine Benutzereingabe. Du kennst anscheinend z.B. das Phänomen Buffer Overflow nicht. |
|
Und Du schreibst Scripts offenbar nur für Dich selbst. Wenn das Dein einziger Antrieb ist ... |
|
Es macht nichts anderes als das, was Du tust, nur an anderer, sichererer Stelle. |
|
Ich möchte beide Situationen einheitlich behandeln und dazu muss ich an irgendeiner Stelle abstrahieren. Die richtige Stelle dafür ist aber nicht der Format-String (jedenfalls nicht in der jetzigen Form), sondern die Konvertierungsfunktion des Wertes, CtoF(). Z.B. so: var temp = 35; alert(format( 'Today the temperature reached %d°' + (bUseFahrenheit ? 'F' : 'C'), bUseFahrenheit ? CtoF(temp) : temp)); Alternativ könnte man einen Konvertierungsbezeichner für printf(3) definieren, etwa `%T' (wäre noch nicht verplant) für °F oder °C je nach Locale: alert(format('Today the temperature reached %T', 35)); format() ruft dann nach Bedarf CtoF() mit dem übergebenen Argument auf und fügt auch die passende Einheit hinzu. |
#6
| |||||||||||
| |||||||||||
|
|
Thomas 'PointedEars' Lahn wrote: Michael Schuerig wrote: Printf ist aber nicht das, was ich haben will. Ich brauche die Funktion zum lokalisieren von Strings mit interpolierten (interpositionierten?) `Interpoliert' sicher nicht. MUSEN schon eher das andere. Anscheinend bezeichnet das aber praktisch jeder und sein Hund |
|
trotzdem als Interpolation. Warum auch immer. |
|
[Nicht maskierte '{' und '}'] Danke. Korrigiert. Dummerweise hat es mit einem Browser doch kompiliert. Schlimm. Mit welchem? Konqueror/kjs |
|
return this.replace( /\{\{[^{}]*\}\}|\{(\d+)(,\s*([\w.]+))?\}/g, ^^^^ ^^^^ ^^ ^^ Also??ß Also was? |
|
"{0,function spamMe() {...}; while (true) {spamMe();};}" Dann war der Benutzer dumm. Eher schlau. Bedenke, dass *Du* die _Sicherheitslücke_ öffnest. Der Cracker muss sie nur ausnutzen. Deshalb wird das Script mit diesem Ansatz wenig bis keine Verbreitung finden, und einen Programmierer, der es (insbesondere, aber nicht nur, für ein kommerzielles Projekt) unverändert einsetzt, muss man als inkompetent einstufen. [schnipp] Der Formatstring ist bei meiner Anwendung immer fest vorgegeben, keine Benutzereingabe. Du kennst anscheinend z.B. das Phänomen Buffer Overflow nicht. Oh, natürlich, ein Cracker könnte es sich noch viel einfacher machen und einfach durch einen Proxy den Formatstring so ändern, dass sein "spamMe" drin steht. Wenn er schon dabei ist, könnte er auch gleich meine ganzen Skripte ignorieren und einfach seine bösen Sachen einbauen. |
|
Und Du schreibst Scripts offenbar nur für Dich selbst. Wenn das Dein einziger Antrieb ist ... Thomas, ich schätze deine sachlichen Kommentare. Solche Bemerkungen könntest du dir sparen. Sie sind unsachlich, reine Spekulation, in ihrer Tendenz darauf angelegt, den Rezipienten als dumm darzustellen. |
|
Zurück zur Sache. Du hältst meinem Ansatz vor, dass er eine Sicherheitslücke öffnet. Ein sorgfältiger(er) Umgang mit diesem Vorwurf ist geboten. |
|
Ich halte deine bisherige Begründung für irrelevant. Ja, es kann bei einer fehlerhaften Implementierung sein, dass eval es ermöglicht, per Buffer-Overflow unerwünschten Code auszuführen. Bedeutsam wäre das, wenn das einem Cracker _neue_ Angriffsmöglichkeiten gäbe. Das tut es nicht. Der Formatstring, in dem auch der eval'te Text enthalten ist, ist fest, keine Benutzereingabe. |
|
Zeige mir ein Szenario, in dem es ein Angreifer gelingt, diesen Formatstring zu ändern -- wo er aber keine andere, einfachere Möglichkeit hat, sein böses Werk zu tun. [...] |
|
Es macht nichts anderes als das, was Du tust, nur an anderer, sichererer Stelle. Die Stelle ist aber wichtig... |
|
[...] var temp = 35; alert(format( 'Today the temperature reached %d°' + (bUseFahrenheit ? 'F' : 'C'), bUseFahrenheit ? CtoF(temp) : temp)); [...] alert(format('Today the temperature reached %T', 35)); format() ruft dann nach Bedarf CtoF() mit dem übergebenen Argument auf und fügt auch die passende Einheit hinzu. Nein. Im ersten Fall wird der Programmcode mit Präsentationslogik (frag mich jetzt nicht, warum das gemeinhin als "Logik" bezeichnet wird) überfrachtet. [...] Der zweite Fall ist nicht erweiterbar, er erfüllt das Open-Closed-Principle nicht. Werden weitere Formate benötigt, muss der Code von format/printf geändert werden, was nicht wünschenswert ist. Stattdessen sollen Erweiterungen _ohne_ Änderungen an bestehendem Code möglich sein. |
#7
| |||||||||||
| |||||||||||
|
|
Thomas 'PointedEars' Lahn wrote: Michael Schuerig wrote: Printf ist aber nicht das, was ich haben will. Ich brauche die Funktion zum lokalisieren von Strings mit interpolierten (interpositionierten?) `Interpoliert' sicher nicht. MUSEN schon eher das andere. Anscheinend bezeichnet das aber praktisch jeder und sein Hund |
|
trotzdem als Interpolation. Warum auch immer. |
|
[Nicht maskierte '{' und '}'] Danke. Korrigiert. Dummerweise hat es mit einem Browser doch kompiliert. Schlimm. Mit welchem? Konqueror/kjs |
|
return this.replace( /\{\{[^{}]*\}\}|\{(\d+)(,\s*([\w.]+))?\}/g, ^^^^ ^^^^ ^^ ^^ Also??ß Also was? |
|
"{0,function spamMe() {...}; while (true) {spamMe();};}" Dann war der Benutzer dumm. Eher schlau. Bedenke, dass *Du* die _Sicherheitslücke_ öffnest. Der Cracker muss sie nur ausnutzen. Deshalb wird das Script mit diesem Ansatz wenig bis keine Verbreitung finden, und einen Programmierer, der es (insbesondere, aber nicht nur, für ein kommerzielles Projekt) unverändert einsetzt, muss man als inkompetent einstufen. [schnipp] Der Formatstring ist bei meiner Anwendung immer fest vorgegeben, keine Benutzereingabe. Du kennst anscheinend z.B. das Phänomen Buffer Overflow nicht. Oh, natürlich, ein Cracker könnte es sich noch viel einfacher machen und einfach durch einen Proxy den Formatstring so ändern, dass sein "spamMe" drin steht. Wenn er schon dabei ist, könnte er auch gleich meine ganzen Skripte ignorieren und einfach seine bösen Sachen einbauen. |
|
Und Du schreibst Scripts offenbar nur für Dich selbst. Wenn das Dein einziger Antrieb ist ... Thomas, ich schätze deine sachlichen Kommentare. Solche Bemerkungen könntest du dir sparen. Sie sind unsachlich, reine Spekulation, in ihrer Tendenz darauf angelegt, den Rezipienten als dumm darzustellen. |
|
Zurück zur Sache. Du hältst meinem Ansatz vor, dass er eine Sicherheitslücke öffnet. Ein sorgfältiger(er) Umgang mit diesem Vorwurf ist geboten. |
|
Ich halte deine bisherige Begründung für irrelevant. Ja, es kann bei einer fehlerhaften Implementierung sein, dass eval es ermöglicht, per Buffer-Overflow unerwünschten Code auszuführen. Bedeutsam wäre das, wenn das einem Cracker _neue_ Angriffsmöglichkeiten gäbe. Das tut es nicht. Der Formatstring, in dem auch der eval'te Text enthalten ist, ist fest, keine Benutzereingabe. |
|
Zeige mir ein Szenario, in dem es ein Angreifer gelingt, diesen Formatstring zu ändern -- wo er aber keine andere, einfachere Möglichkeit hat, sein böses Werk zu tun. [...] |
|
Es macht nichts anderes als das, was Du tust, nur an anderer, sichererer Stelle. Die Stelle ist aber wichtig... |
|
[...] var temp = 35; alert(format( 'Today the temperature reached %d°' + (bUseFahrenheit ? 'F' : 'C'), bUseFahrenheit ? CtoF(temp) : temp)); [...] alert(format('Today the temperature reached %T', 35)); format() ruft dann nach Bedarf CtoF() mit dem übergebenen Argument auf und fügt auch die passende Einheit hinzu. Nein. Im ersten Fall wird der Programmcode mit Präsentationslogik (frag mich jetzt nicht, warum das gemeinhin als "Logik" bezeichnet wird) überfrachtet. [...] Der zweite Fall ist nicht erweiterbar, er erfüllt das Open-Closed-Principle nicht. Werden weitere Formate benötigt, muss der Code von format/printf geändert werden, was nicht wünschenswert ist. Stattdessen sollen Erweiterungen _ohne_ Änderungen an bestehendem Code möglich sein. |
#8
| |||||||
| |||||||
|
|
Michael Schuerig wrote: Thomas 'PointedEars' Lahn wrote: Michael Schuerig wrote: Printf ist aber nicht das, was ich haben will. Ich brauche die Funktion zum lokalisieren von Strings mit interpolierten (interpositionierten?) `Interpoliert' sicher nicht. MUSEN schon eher das andere. Anscheinend bezeichnet das aber praktisch jeder und sein Hund Die sind mir nicht bekannt. trotzdem als Interpolation. Warum auch immer. Das kommt darauf an, was Du damit meinst. MUSEN ist Interpolation ein mathematisches Verfahren (<http://de.wikipedia.org/wiki/Interpolation>). Interposition (Dazwischenanordnung) ist MUSEN das, was Du mit den Variablenwerten im String vorhast. |
|
Konqueror/kjs Ich habe hier auch Konqueror. Mit welcher Version hast Du genau getestet? |
|
Der Formatstring, in dem auch der eval'te Text enthalten ist, ist fest, keine Benutzereingabe. Das ist in *Deiner* Anwendung Deiner Methode so. Wenn aber jemand Deine Methode wiederverwenden möchte, kann er damit nicht guten Gewissens Benutzereingaben formatieren, weil die von Dir geschaffene Sicherheitslücke existiert. |
|
Damit ist Dein Code nicht allgemein brauchbar und daher von geringerem Wert als universell einsetzbarer Code. |
|
Zeige mir ein Szenario, in dem es ein Angreifer gelingt, diesen Formatstring zu ändern -- wo er aber keine andere, einfachere Möglichkeit hat, sein böses Werk zu tun. [...] Nein. Es geht hierbei ums (Programmier-)Prinzip: Bei gutem Design werden solche Fallen erkannt und durch eine geeignete Implementation von vornherein vermieden. Nicht umsonst heisst es: eval is evil, und zwar nicht nur in JS. Google ist Dein Freund. [psf 6.1] |
|
Es macht nichts anderes als das, was Du tust, nur an anderer, sichererer Stelle. Die Stelle ist aber wichtig... Ja, es ist wichtig, dass die andere Stelle sicherer ist, denn das beeinflusst wesentlich die Codequalität. |
|
Man kann eben nicht alles haben. [psf 3.2] |
#9
| |||
| |||
|
|
Michael Schuerig wrote: Thomas 'PointedEars' Lahn wrote: [Nicht maskierte '{' und '}'] Danke. Korrigiert. Dummerweise hat es mit einem Browser doch kompiliert. Schlimm. Mit welchem? Konqueror/kjs Ich habe hier auch Konqueror. Mit welcher Version hast Du genau getestet? |
|
[...] REPETITION A closing brace on its own is not a special character. [...] An opening curly bracket that appears in a position where a quantifier is not allowed, or one that does not match the syntax of a quantifier, is taken as a literal character. For example, {,6} is not a quantifier, but a literal string of four characters. [...] |
|
[...] 15.10.1 Patterns The RegExp constructor applies the following grammar to the input pattern string. An error occurs if the grammar cannot interpret the string as an expansion of Pattern. Syntax Pattern :: Disjunction Disjunction :: Alternative Alternative | Disjunction Alternative :: [empty] Alternative Term Term :: Assertion Atom Atom Quantifier Assertion :: ^ $ \ b \ B Quantifier :: QuantifierPrefix QuantifierPrefix ? QuantifierPrefix :: * + ? { DecimalDigits } { DecimalDigits , } { DecimalDigits , DecimalDigits } Atom :: PatternCharacter . \ AtomEscape CharacterClass ( Disjunction ) ( ? : Disjunction ) ( ? = Disjunction ) ( ? ! Disjunction ) PatternCharacter :: SourceCharacter but not any of: ^ $ \ . * + ? ( ) [ ] { } | |
#10
| ||||
| ||||
|
|
Thomas 'PointedEars' Lahn wrote: Michael Schuerig wrote: [{{ ist im Testbrowser eine gültige RegExp] Ich habe hier auch Konqueror. Mit welcher Version hast Du genau getestet? 3.4.0 |
|
Der Formatstring, in dem auch der eval'te Text enthalten ist, ist fest, keine Benutzereingabe. Das ist in *Deiner* Anwendung Deiner Methode so. Wenn aber jemand Deine Methode wiederverwenden möchte, kann er damit nicht guten Gewissens Benutzereingaben formatieren, weil die von Dir geschaffene Sicherheitslücke existiert. Das ist richtig und dazu ist die Methode nicht gedacht. Du wirst in C einem Benutzer auch nicht guten Gewissens die Möglichkeit geben, den Formatstring für ein printf zu definieren. |
|
Es geht hierbei ums (Programmier-)Prinzip: Bei gutem Design werden solche Fallen erkannt und durch eine geeignete Implementation von vornherein vermieden. Nicht umsonst heisst es: eval is evil, und zwar nicht nur in JS. Google ist Dein Freund. [psf 6.1] Ich weiss, das eval in vielen Situationen bösartig ist. Es ist nicht auszuschliessen, dass ich das schon länger weiss, als du überhaupt programmierst. [...] |
|
Damit ist Dein Code nicht allgemein brauchbar und daher von geringerem Wert als universell einsetzbarer Code. Den "universell einsetzbaren Code", der gleich mächtig ist, habe ich aber noch nicht gesehen. |

![]() |
| Thread Tools | |
| Display Modes | |
| |