Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Floattostr wandelt Komma in #0 (https://www.delphipraxis.net/184695-floattostr-wandelt-komma-0-a.html)

ioster 15. Apr 2015 10:39

Floattostr wandelt Komma in #0
 
Ich habe eine Anwendung in Bearbeitung, die ich vor ein paar Jahren geschrieben habe. Dabei handelt es sich um eine Preiskalkulation, die mit einem Formelparser auch Feldinhalte mittels Formeln errechnen kann. Aufgemacht habe ich das Projekt, weil Änderungen gewünscht werden, die den eigentlichen Kern der Berechnungen gar nicht betreffen.

Nun habe ich aber das Problem, das an einer Stelle, an der Feldwerte mit SysUtils.FloatToStr in eine Zeichenkette umgewandelt werden, um in eine Formel einen Platzhalter ersetzen zu können, plötzlich merkwürdige Ergebnisse herauskommen.

Aus 4,5887305339 macht die Funktion '4'#0'58873053386861'. Das dabei Berechnungen auf die Bretter gehen, dürfte klar sein. Nur warum wird aus einem Komma "#0"?

Mit der Entwicklungsumgebung DELPHI 2007 arbeite ich tagtäglich. Komponenten sind auch nicht hinzugekommen. Der Wert wird in einer KbmMemtable Version 7.18.00 gespeichert.

Ich muss allerdings dazu sagen, dass ich auf dem PC .NET Framework 4.0 installieren musste, weil es mein Virenscanner von Kasperky verlangte. Kann das die Delphi-Routinen beeinflussen? Ich arbeite schon etliche Jahre mit DELPHI, habe so etwas aber auch noch nicht gesehen.

Gruß
Ingo

mkinzler 15. Apr 2015 10:42

AW: Floattostr wandelt Komma in #0
 
Ich vermute mal das ist ein Unicodeproblem. Ändere sden Typ mal auf AnsiString

Der schöne Günther 15. Apr 2015 10:44

AW: Floattostr wandelt Komma in #0
 
Verstehe nicht was Unicode damit zu tun haben soll. Ich hätte eigentlich gedacht dass du entweder deine Anwendungs-eigenen FormatSettings.DecimalSeparator umgestellt hast (wohl kaum, aber prüfe das doch mal), oder jemand deinen windows-weiten Decimalseparator.

mkinzler 15. Apr 2015 10:52

AW: Floattostr wandelt Komma in #0
 
#0 in Strings weissen im Allgemeinen auf Unicode hin.

DeddyH 15. Apr 2015 10:53

AW: Floattostr wandelt Komma in #0
 
Mit Delphi 2007? Das müsste dann aber irgendwas Selbstgestricktes sein.

ioster 15. Apr 2015 10:58

AW: Floattostr wandelt Komma in #0
 
Zitat:

Zitat von DeddyH (Beitrag 1297803)
Mit Delphi 2007? Das müsste dann aber irgendwas Selbstgestricktes sein.

Nein - Selbstgestricktes in Richtung Unicode ist nicht dabei. Ich habe jetzt den numerischen Wert direkt in die Funktion gegeben und einen korrekten String zurückerhalten. Als nächstes versuche ich es einmal mit einem Zugriff auf eine reelle Tabelle. Dann kann "nur" noch die Memtable das Problem erzeugen. Die Sourcen können natürlich inzwischen Schalter für Unicode haben. Das entzieht sich aber meiner Kenntnis.

Danke schon 'mal für die schnellen Antworten und Tipps.

Gruß
Ingo

Popov 15. Apr 2015 11:01

AW: Floattostr wandelt Komma in #0
 
Zitat:

Aus 4,5887305339 macht die Funktion '4'#0'58873053386861'. Das dabei Berechnungen auf die Bretter gehen, dürfte klar sein. Nur warum wird aus einem Komma "#0"?
Warum gehen Berechnungen auf die Bretter, weil du mit FloatToStr einen String generierst? Ob im String die Zahl ob die erste Zeile von Pippi Langstrumpf Lied steht, sollte dem Programm doch egal sein, denn du rechnest ja mit der Zahl und nicht mit dem String. Andersherum wäre es kritisch.

Aber egal. Ich weiß nicht warum, aber anscheinend steht irgendwo in den Einstellung ein #0 als Dezimaltzrennzeichen eingetragen.

Wenn du entscheiden willst was das Dezimaltrennzeichen sein soll, dann musst du es der Formel sagen. Hier mal aus dem Kopf:
Delphi-Quellcode:
var
  d: Double;
  fs: TFormatSettings;
  s: string;
begin
  d := 4.5887305339;
  fs.DecimalSeparator := ',';
  s := FloatToStr(d, fs);
  ShowMessage(s);
Nun weiß Delphi was gewünscht ist.

himitsu 15. Apr 2015 11:06

AW: Floattostr wandelt Komma in #0
 
Ich vermute auch eher, daß dort das globale FormatSettings futsch ist. -> "jemand" hat #0 als Dezimaltrenner deklariert
* Tausendertrenner = #0 geht, denn das besagt, daß es keinen Tausendertrenner gibt (Dezimaltrenner gibt es aber immer)
* oder jemand übergibt ein defektes FormatSettings via Parameter an FloatToStr.

ioster 15. Apr 2015 11:08

AW: Floattostr wandelt Komma in #0
 
Zitat:

Zitat von Popov (Beitrag 1297805)
Zitat:

Aus 4,5887305339 macht die Funktion '4'#0'58873053386861'. Das dabei Berechnungen auf die Bretter gehen, dürfte klar sein. Nur warum wird aus einem Komma "#0"?
Warum gehen Berechnungen auf die Bretter, weil du mit FloatToStr einen String generierst? Ob im String die Zahl ob die erste Zeile von Pippi Langstrumpf Lied steht, sollte dem Programm doch egal sein, denn du rechnest ja mit der Zahl und nicht mit dem String. Andersherum wäre es kritisch.

Die Berechnungen gehen auf die Bretter, weil die Werte in fertige Formeln eingesetzt werden also

"[Fertigungskosten] + [Materialzuschlag]" => "10 + 4'#0'58873053386861"

Dieser String wird dann in einen Formelparser weitergereicht, der dann den numerischen Wert zurückgibt.

Gruß
Ingo

Popov 15. Apr 2015 11:25

AW: Floattostr wandelt Komma in #0
 
Verstehe. Aber wenn du mit einem Parser arbeitest, ist es um so wichtiger mit TFormatSettings zu arbeiten, denn sonst arbeitet das Programm nur zufällig richtig. Denn wenn dein Parser ein Komma "," als Dezimaltrennzeichen erwartet und plötzlich arbeitet ein Schweizer damit (da ist es üblich Punkt "." als Trennzeichen zu nehmen), gibt es Probleme.

ioster 15. Apr 2015 11:42

AW: Floattostr wandelt Komma in #0
 
Zitat:

Zitat von Popov (Beitrag 1297809)
Verstehe. Aber wenn du mit einem Parser arbeitest, ist es um so wichtiger mit TFormatSettings zu arbeiten, denn sonst arbeitet das Programm nur zufällig richtig. Denn wenn dein Parser ein Komma "," als Dezimaltrennzeichen erwartet und plötzlich arbeitet ein Schweizer damit (da ist es üblich Punkt "." als Trennzeichen zu nehmen), gibt es Probleme.

Ja - das Schwizer Problem habe ich schon in einem anderen Projekt gehabt. Dort hat man sich noch mehr auf "." und "," verlassen und als dann die Anwendung auf Schweizer Zahlenformat gestellt war, kamen nicht unerhebliche Rundungen zustande :-D Die haben als Tausenderzeichen ein Hochkomma und als Dezimaltrenner den Punkt.

Nun - das mit den Formatsettings ist der entscheidende Tipp gewesen. Dort steht als Dezimaltrenner tatsächlich #0 drin, wobei ich mir nicht erklären kann, an welcher Stelle das geändert worden sein kann. Ich habe nun Deinen Hinweis mit der Definition des Dezimaltrenners vor die Funktion gesetzt und alles ist gut. Jetzt spuckt der Parser, aber das ist das Folgeproblem, auf das Du an dieser Stelle hingewiesen hast.

Ich denke, wir können den Thread hiermit zumachen. Danke für Eure Tipps.

Gruß
Ingo

himitsu 15. Apr 2015 12:27

AW: Floattostr wandelt Komma in #0
 
Zitat:

Zitat von ioster (Beitrag 1297813)
Ich habe nun Deinen Hinweis mit der Definition des Dezimaltrenners vor die Funktion gesetzt und alles ist gut.

Ich hoffe du hast nicht die globale Variable davor geändert, denn genau das wäre falsch/fatal.

Es wird nicht umsonst gesagt, daß globale Variablen böse sind.
Und man sollte niemals grundlos an globalen Settings rumschrauben. :warn:

Zuerst suchst du mal, wo dein Setting kaputt geht und reparierst das.
Und dann benutzt du dort, wo du selber mit einem "Sonderformat" hantierst, den Settings-Parameter der jeweiligen Umwandlungsfunktionen.
Delphi-Referenz durchsuchenFloatToStr

ioster 15. Apr 2015 13:27

AW: Floattostr wandelt Komma in #0
 
Ich habe jetzt eine Funktion ausgeklammert, die die Ergebnisse der Berechnung mit SMExport-Komponenten abspeichert. Die scheint in ihren Tiefen eine Umformatierung des Settings vorzunehmen. Werde den Support von Scalabium dazu befragen. Merkwürdig nur, dass das mit einem Mal so auftaucht und bisher in keinem anderen Projekt Probleme verursacht hat.

Gruß
Ingo

Popov 15. Apr 2015 13:41

AW: Floattostr wandelt Komma in #0
 
Zitat:

Die scheint in ihren Tiefen eine Umformatierung des Settings vorzunehmen.
ioster, das ist egal. Nicht wirklich wichtig. Deshalb gibt es auch die erweiterten StrToFloat, FloatToStr, StrToDate, DateToStr, usw. Funktionen. Es gibt immer die einfache Version, die man nehmen kann, die aber nicht sicher ist, da sie dann mit den länderspezifischen Separatoren arbeiten, und die erweitere.

Selbst wenn da irgendwo in den Tiefen eine Änderung vorgenommen wird, wenn man mit eigenen TFormatSettings arbeitet, erlebt man keine Überschungen.

himitsu 15. Apr 2015 13:54

AW: Floattostr wandelt Komma in #0
 
Sicher sind die einfachen Funktionen schon.
Wenn man eine Zahl so ausgibt und auch so wieder einliest, dann gibt es keine Probleme, da ja das selbe Setting wieder benutzt wird.

Wenn man aber ein bestimmtes Format benötigt oder wenn man Daten speichern, bzw. übertragen (anderes Programm/Rechner) will,
dann muß man Dieses immer in einem definierten Format tun. (oder muß das Format mit übergeben, bei Speicherung/Übertragung)

ioster 15. Apr 2015 15:22

AW: Floattostr wandelt Komma in #0
 
Zitat:

Zitat von Popov (Beitrag 1297846)
Zitat:

Die scheint in ihren Tiefen eine Umformatierung des Settings vorzunehmen.
ioster, das ist egal. Nicht wirklich wichtig. Deshalb gibt es auch die erweiterten StrToFloat, FloatToStr, StrToDate, DateToStr, usw. Funktionen. Es gibt immer die einfache Version, die man nehmen kann, die aber nicht sicher ist, da sie dann mit den länderspezifischen Separatoren arbeiten, und die erweitere.

Selbst wenn da irgendwo in den Tiefen eine Änderung vorgenommen wird, wenn man mit eigenen TFormatSettings arbeitet, erlebt man keine Überschungen.

Ich muss nochmal ganz blöd nachfragen, was TFormatSettings betrifft, weil ich da bisher nicht mit gearbeitet habe. Wenn ich das Beispiel von popov nutze, manipuliere ich dann die Standardeinstellungen des Systems? Muss ich mir mit TFormatSettings.Create eine eigene erstellen, die ich dann für Funktionsaufrufe nutze?

Das Programm läuft nun, nachdem ich in meiner Funktion vor FloatToStr die Separatoren umsetze. Allerdings musste ich dasselbe im Formelparser machen, weil dort StrToFloat aufgerufen wird. Das ging durch die Anpassungen auch in die Hose.

mkinzler 15. Apr 2015 15:55

AW: Floattostr wandelt Komma in #0
 
Es gibt überladene Versionen der <Typ>To<Typ> bzw. Try<Typ>To<Typ> welche man das Format als weiteren Parameter mitgeben kann.

http://www.delphibasics.co.uk/RTL.as...FormatSettings

himitsu 15. Apr 2015 16:11

AW: Floattostr wandelt Komma in #0
 
Also, zum Glück nicht die des Systems, sondern nur die des Programms (EXE), solange wie diese läuft.
Beim nächsten Programmstart werden die Einstellungen vom System ausgelesen und in das programm-globale FormatSettings geschrieben/kopiert.

Achtung, wenn man mit der VCL/FMX arbeitet (nicht in der Console, da dort keine Messages verarbeitet werden), dann reagiert Delphi z.B. auf WM_INICHANGE, welches vom Windows an alle Programme verschickt wird, wenn jemand z.B. diese Settings im Windows ändert, und läd die Einstellungen neu. (hast du das global geändert, ist es danach wieder weg)

Popov 15. Apr 2015 18:34

AW: Floattostr wandelt Komma in #0
 
Zitat:

Zitat von ioster (Beitrag 1297888)
Wenn ich das Beispiel von popov nutze, manipuliere ich dann die Standardeinstellungen des Systems?

Weder die des Systems, noch die des Programms. Nur die eines Records.

Zuerst, nicht alles was ein T am Anfang hat ist eine Klasse. TFormatSettings ist hier ein Record:
Delphi-Quellcode:
type
  TFormatSettings = record
    CurrencyFormat: Byte;
    NegCurrFormat: Byte;
    ThousandSeparator: Char;
    DecimalSeparator: Char;
    CurrencyDecimals: Byte;
    DateSeparator: Char;
    TimeSeparator: Char;
    ListSeparator: Char;
    CurrencyString: string;
    ShortDateFormat: string;
    LongDateFormat: string;
    TimeAMString: string;
    TimePMString: string;
    ShortTimeFormat: string;
    LongTimeFormat: string;
    ShortMonthNames: array[1..12] of string;
    LongMonthNames: array[1..12] of string;
    ShortDayNames: array[1..7] of string;
    LongDayNames: array[1..7] of string;
    TwoDigitYearCenturyWindow: Word;
  end;
Eigentlich ist das Beispiel was ich am Anfang geschrieben habe nicht ganz korrekt, denn bei
Delphi-Quellcode:
var
  d: Double;
  fs: TFormatSettings;
  s: string;
begin
  d := 4.5887305339;
  fs.DecimalSeparator := ',';
  s := FloatToStr(d, fs);
steht in fs nur Müll. Auf jeden Fall nicht die in Deutschland gültigen Ländereinstellungen. Sollte man nicht machen, man sollte zuerst GetLocaleFormatSettings(LOCALE_SYSTEM_DEFAULT, fs); aufrufen. Das ist aber in dem Fall nicht so wichtig, denn mit der Zeile
Delphi-Quellcode:
fs.DecimalSeparator := ',';
habe ich den für mich wichtigen Wert angepasst. Und wenn ich es nun mitschicke, weiß FloatToStr, dass ich ein Komma als Dezimalseparator ansehe. Danach kann ich den fs Record vergessen. Es gab keine Änderungen irgendwo, nur in fs.

Zitat:

Muss ich mir mit TFormatSettings.Create eine eigene erstellen
Nein, sofort nutzen.

himitsu 15. Apr 2015 19:16

AW: Floattostr wandelt Komma in #0
 
Zitat:

Zitat von Popov (Beitrag 1297911)
Zitat:

Muss ich mir mit TFormatSettings.Create eine eigene erstellen
Nein, sofort nutzen.

Jupp, dieses Create ist quasi sowas, wie eine Class-Function, welche einen "initialisieren" Record zurückgibt.
Ohne Parameter mit den aktullen Systemeinstellungen und mit einem Parameter kann man auch direkt ein bestimmtes Setting laden. (aus den Sprachen/Locales, welche dein Windows kennt)
Den Record kann man sich in seine Variable kopieren (
Delphi-Quellcode:
:=
) oder direkt in den Parameter reingeben.

Im Notfall reicht es, wenn man "nur" die Felder des Records füllt, welche die jeweilige Funktion verwenden/benötigen.
Bei Integer/Floatwerten wären es das Komma und das Tausenderzeichen, für Currency zusätzlich auch noch die 3 Werte Geld-Felder, für Datumsfunktionen die Datums- und Zeitfelder usw.

Aber man hätte natürlich auch mal ganz einfach in die OH zu schauen brauchen. :roll:

Dejan Vu 16. Apr 2015 07:28

AW: Floattostr wandelt Komma in #0
 
Aus einer Formel '[Material]*[Zuschlag]' zuerst einen String '10*23.456' zu generieren, ist auch lustig.
Ich hätte den Parser so modifiziert, das er die Platzhalter erkennt und direkt dort die Werte 'abfragt'.

Aber gut. So geht's ja auch (und ist auch ok).


Alle Zeitangaben in WEZ +1. Es ist jetzt 01:08 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz