[Gelöst] Warum funktioniert StrToFloat('1.234,56') nicht?

Für Fragen von Einsteigern und Programmieranfängern...
kirchfritz
Beiträge: 168
Registriert: Mo 3. Jan 2011, 13:34
OS, Lazarus, FPC: Win10 (L 3.0 FPC 3.2.2)
CPU-Target: 64Bit
Wohnort: Nürnberg

[Gelöst] Warum funktioniert StrToFloat('1.234,56') nicht?

Beitrag von kirchfritz »

Hallo,

ich möchte meine Zeichenkette '1.234,56' in ein Double umwandeln mit Hilfe der Funktion StrToFloat.
Deshalb habe ich mir eigens eine Umwandlungsfunktion geschrieben, die lokalen Formatsettings (dort sind DecimalSeparator auf KOMMA und ThousandSeparator auf PUNKT gesetzt) verwendet:

Code: Alles auswählen

function MyStrToFloat(const s : String) : Double;
begin
  try
    result := StrToFloat(s ,DefaultFormatSettings);
  except
    result := 0;
  end;
end;  
Leider bekomme ich nur die Fehlermeldung
"1.234,56" is an invalid float

Was mache ich falsch?

WIN10, LAZARUS 2.2.4 FPC: 3.2.2

TestProjekt im Anhang
Dateianhänge
StrToFloatProblem.zip
(138.69 KiB) 26-mal heruntergeladen
Zuletzt geändert von kirchfritz am Di 31. Jan 2023, 16:54, insgesamt 1-mal geändert.

Benutzeravatar
theo
Beiträge: 10461
Registriert: Mo 11. Sep 2006, 19:01

Re: Warum funktioniert StrToFloat('1.234,56') nicht?

Beitrag von theo »

RTFM: https://www.freepascal.org/docs-html/rt ... float.html :wink:
The thousandseparator character may however not be used.

Mathias
Beiträge: 6144
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Warum funktioniert StrToFloat('1.234,56') nicht?

Beitrag von Mathias »

theo hat geschrieben:
Di 31. Jan 2023, 16:31
RTFM: https://www.freepascal.org/docs-html/rt ... float.html :wink:
The thousandseparator character may however not be used.
Da bleibt einem wohl nicht viel übrig, als den Tausendertrennner mit StringReplace zu entfernen.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

kirchfritz
Beiträge: 168
Registriert: Mo 3. Jan 2011, 13:34
OS, Lazarus, FPC: Win10 (L 3.0 FPC 3.2.2)
CPU-Target: 64Bit
Wohnort: Nürnberg

Re: Warum funktioniert StrToFloat('1.234,56') nicht?

Beitrag von kirchfritz »

Da hätte ich wohl besser das fu...ing Manual gelesen.
Danke für Eure Ermunterung.
Mein Problem ist durch Löschen (bzw. Nichtverwenden ) des Tausendertrennzeichens gelöst.

Benutzeravatar
six1
Beiträge: 782
Registriert: Do 1. Jul 2010, 19:01

Re: [Gelöst] Warum funktioniert StrToFloat('1.234,56') nicht?

Beitrag von six1 »

...und wenn durch Sprachumschaltung des System das Komma zum Punkt wird?
Du solltest die Werte abfragen oder explizit zuweisen!

// Punkt als Dezimaltrennzeichen
DefaultFormatSettings.DecimalSeparator := '.';

// Komma als Dezimaltrennzeichen
DefaultFormatSettings.DecimalSeparator := ';';

// Beliebiges Zeichen als Dezimaltrennzeichen
DefaultFormatSettings.DecimalSeparator := '|';

DefaultFormatSettings.ThousandSeparator
Gruß, Michael

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6197
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: [Gelöst] Warum funktioniert StrToFloat('1.234,56') nicht?

Beitrag von af0815 »

BTW: Lazarus könnte ohne Probleme auch mit tausender Seperator umgehen, ABER Delphi hat da einen Bug gehabt, damit heisst es "Won't fix, it is Delphi compatible" DIe Diskussion habe ich schon vor Jahren gehabt. So um den Zeitpunkt, wo ich mich hier registriert habe, sind also auch schon ein paar Tage her.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Benutzeravatar
theo
Beiträge: 10461
Registriert: Mo 11. Sep 2006, 19:01

Re: [Gelöst] Warum funktioniert StrToFloat('1.234,56') nicht?

Beitrag von theo »

Naja, die Umwandlung an sich ist ja nicht das Problem.
Das Problem ist, dass der Input je nach Herkunft variiert und man gar nicht so einfach bestimmen kann, was vorliegt.
Wenn ich mir die KDE Einstellungen anschaue, gibt es nur schon in D, A und CH jeweils unterschiedlich Standards.

formatsettings.png
formatsettings.png (41.62 KiB) 1013 mal betrachtet

Benutzeravatar
Winni
Beiträge: 1577
Registriert: Mo 2. Mär 2009, 16:45
OS, Lazarus, FPC: Laz2.2.2, fpc 3.2.2
CPU-Target: 64Bit
Wohnort: Fast Dänemark

Re: [Gelöst] Warum funktioniert StrToFloat('1.234,56') nicht?

Beitrag von Winni »

theo hat geschrieben:
Di 31. Jan 2023, 18:08
Wenn ich mir die KDE Einstellungen anschaue, gibt es nur schon in D, A und CH jeweils unterschiedlich Standards.
Hi!

Da liegt ja auch der riesige Bodensee dazwischen.
In Konstanz sagen sie dazu "Meer".

Der Norddeutsche schmunzelt und schüttelt den Kopf.

Winni

siro
Beiträge: 730
Registriert: Di 23. Aug 2016, 14:25
OS, Lazarus, FPC: Windows 11
CPU-Target: 64Bit
Wohnort: Berlin

Re: [Gelöst] Warum funktioniert StrToFloat('1.234,56') nicht?

Beitrag von siro »

Ich hatte auch schon mal rumprobiert mit dem TryStrToFloat:

Code: Alles auswählen

procedure Test;
var s:string;   value:Double;
begin
  s:='3,14';      // Okay Komma wenn DefaultFormatSettings.DecimalSeparator ein Komma ist
  s:='3.14';      // Okay Punkt wenn DefaultFormatSettings.DecimalSeparator auf Punkt umgestellt wurde
  s:='3:14';      // klappt weder noch

  if TryStrToFloat(s,value) then Form1.caption:='Okay Komma'
  else begin
    DefaultFormatSettings.DecimalSeparator:='.';    // Separator auf Punkt setzen
    if TryStrToFloat(s,value) then Form1.caption:='Okay Punkt'
    else Form1.caption:='Klappt weder noch';
  end;
end;

im folgenden Code wird der Exeption NUR in der Entwicklungsumgebung erzeugt,
ruft man die .exe Datei direkt auf, dann gibt es keinen Exeption
procedure TForm1.FormCreate(Sender: TObject);
var s:string;   value:Double;
begin
//  Test;
  s:='3.14';
  try
    value:=StrToFloat(s);                           // hier wird ein Fehler ausgelöst
  except
    caption:='Conversion Error';
    DefaultFormatSettings.DecimalSeparator:='.';    // Separator auf Punkt setzen
  end;
  value:=StrToFloat(s);                             // nun sollte es gehen
end;
                
Grüße von Siro
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...

Mathias
Beiträge: 6144
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: [Gelöst] Warum funktioniert StrToFloat('1.234,56') nicht?

Beitrag von Mathias »

Wenn ich mir die KDE Einstellungen anschaue, gibt es nur schon in D, A und CH jeweils unterschiedlich Standards.
Ich dachte, AT und DE machen es gleich, anscheinend habe ich mich getäuscht. 8)
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6197
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: [Gelöst] Warum funktioniert StrToFloat('1.234,56') nicht?

Beitrag von af0815 »

Irgendwo in dem Forum ist eine geniale Funktion versteckt, die so ziemlich alles frisst (wenn ich mich richtig erinnere), ich finde es nur leider nicht. Der Funktion war es egal ob Punkt oder Beistrich. Vielleicht findet wer die noch.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Benutzeravatar
theo
Beiträge: 10461
Registriert: Mo 11. Sep 2006, 19:01

Re: [Gelöst] Warum funktioniert StrToFloat('1.234,56') nicht?

Beitrag von theo »

Winni hat geschrieben:
Di 31. Jan 2023, 18:20
Da liegt ja auch der riesige Bodensee dazwischen.
In Konstanz sagen sie dazu "Meer".
:lol:
Der CH-Standard ist natürlich der einzig Vernünftige.
Zweimal unten ist genau so bescheuert wie ein Leerschlag dazwischen. :mrgreen: :lol:

Mathias
Beiträge: 6144
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: [Gelöst] Warum funktioniert StrToFloat('1.234,56') nicht?

Beitrag von Mathias »

theo hat geschrieben:
Di 31. Jan 2023, 18:50
Winni hat geschrieben:
Di 31. Jan 2023, 18:20
Da liegt ja auch der riesige Bodensee dazwischen.
In Konstanz sagen sie dazu "Meer".
:lol:
Der CH-Standard ist natürlich der einzig Vernünftige.
Zweimal unten ist genau so bescheuert wie ein Leerschlag dazwischen. :mrgreen: :lol:
Genau so ist es, auch das Komma als Dezimaltrenner
Finde ich bescheuert. Ein riessenmurks nur für die Bürolisten, welche das Komma lieben,
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Benutzeravatar
Winni
Beiträge: 1577
Registriert: Mo 2. Mär 2009, 16:45
OS, Lazarus, FPC: Laz2.2.2, fpc 3.2.2
CPU-Target: 64Bit
Wohnort: Fast Dänemark

Re: [Gelöst] Warum funktioniert StrToFloat('1.234,56') nicht?

Beitrag von Winni »

Hi!

Ich hatte mir mal selbst eine Funktion gebaut, die alle Tausender-Trenner frisst.
Egal was. Muss allerdings ein Char sein und kein UTF8Char.

Der Dezimal-Trenner wird vom System abgeholt.
Der andere muss der 1000-Trenner sein.
Egal ob Punkt, Komma, Hochkomma, Space.

Code: Alles auswählen

function InternationalStr2Float(s: string) : single;
var decSep: char;
    Sep1000: char;
    i : Integer;

    procedure KillChar (var st : string; killme: char);
    var p : Integer;
    begin
    repeat
      p := pos (killme,st);
      if p > 0 then delete (st,p,1);
    until p=0;
    end;

    begin //InternationalStr2Float
     decSep := DefaultFormatSettings.DecimalSeparator;
     for i := 1 to length(s) do
       if NOT (s[i] in ['0'..'9',decSep]) then Sep1000 := s[i];
     killchar(s,sep1000);
     result := StrToFloat(s);
    end;
            

Grüße
Winni

kirchfritz
Beiträge: 168
Registriert: Mo 3. Jan 2011, 13:34
OS, Lazarus, FPC: Win10 (L 3.0 FPC 3.2.2)
CPU-Target: 64Bit
Wohnort: Nürnberg

Re: [Gelöst] Warum funktioniert StrToFloat('1.234,56') nicht?

Beitrag von kirchfritz »

Hallo,

ich habe mal versucht in den Quellen von FPC nach StrToFloat zu forschen und bin hier fündig geworden:

\fpcsrc\rtl\objpas\sysutils\sysstr.inc"

Dort liest man folgendes:

Code: Alles auswählen

Function StrToFloat(Const S : String; Const FormatSettings: TFormatSettings) : Extended;
Begin // texttofloat handles NIL properly
  If Not TextToFloat(Pchar(pointer(S)),Result,FormatSettings) then
    Raise EConvertError.createfmt(SInValidFLoat,[S]);
End;
Also StrToFloat ruft TextToFloat auf. Soweit verstanden...
Und das hier ist TextToFloat

Code: Alles auswählen

Function TextToFloat(Buffer: PChar; Out Value: Extended; Const FormatSettings: TFormatSettings): Boolean;
Var
  E,P : Integer;
  S : String;
Begin
  S:=StrPas(Buffer);
  //ThousandSeparator not allowed as by Delphi specs
  if (FormatSettings.ThousandSeparator <> FormatSettings.DecimalSeparator) and
     (Pos(FormatSettings.ThousandSeparator, S) <> 0) then
    begin
      Result := False;
      Exit;
    end;
  if (FormatSettings.DecimalSeparator <> '.') and
     (Pos('.', S) <>0) then
    begin
      Result := False;
      Exit;
    end;
  P:=Pos(FormatSettings.DecimalSeparator,S);
  If (P<>0) Then
    S[P] := '.';
  try
    Val(trim(S),Value,E);
  { on x87, a floating point exception may be pending in case of an invalid
    input value -> trigger it now }
{$if defined(cpui386) or (defined(cpux86_64) and not(defined(win64))) or defined(cpui8086)}
    asm
      fwait
    end;
{$endif}
  except
    E:=1;
  end;
  Result:=(E=0);
End;

Antworten