Convert string with commas to float
Asked Answered
H

10

12

Is there a built-in Delphi function which would convert a string such as '3,232.00' to float? StrToFloat raises an exception because of the comma. Or is the only way to strip out the comma first and then do StrToFloat?

Thanks.

Haggard answered 25/4, 2009 at 2:33 Comment(1)
Is there any requirement for this to work in locales where the comma is used as a decimal point? Anywhere in Europe, for example?Cuirbouilli
G
15

Do you exactly know, that '.' is decimal separator and ',' is thousand separator (always)? If so, then you should fill the TFormatSettings record and pass it to StrToFloat.

FillChar(FS, SizeOf(FS), 0);
... // filling other fields
FS.ThousandSeparator := ',';
FS.DecimalSeparator := '.';
V := StrToFloat(S, FS);
Geronimo answered 25/4, 2009 at 6:56 Comment(7)
Assuming you are on Delphi 7 or higher, otherwise the formatsettings argument is not available, and StrToFloat happily ignores any thousandseparator you set.Eutectoid
Is FillChar(FS, SizeOf(FS), 0); really necessary? It seems to work also without (Delphi XE2).Andi
@Andi Yes, it is necessary. It can work, but only by coincedense. That is: either you fill ALL fields (and no new fields are added in next Delphi version), or a garbage which is in FS is not used by StrToFloat. Since you have little control over Delphi RTL - you should zero unused fields.Geronimo
This doesn't work on XE6. The help file for StrToFloat specifically says, "Thousand separators and currency symbols are not allowed in the string." Including the format settings doesn't seem to have any effect on this.Cobbett
StrToFloat() in D7 doesn't work for thousands separators (commas, spaces, periods (French), etc.), regardless for the TFormatSettings passed in. They need to be stripped out first (see StringReplace in another answer). I'm surprised this was marked as a solution. Does it work for anyone else in some other version? StrToFloat() does use the TFormatSettings decimal separator passed in, but that wasn't the question here.Bedtime
I'm talking about this line: FillChar(FS, SizeOf(FS), 0); , Did you create a variable? Because, I tried to put FillChar(FormatSettings, SizeOf(FormatSetting), 0); and when I closed my SW appears some leak memory issues?Parodist
@WellingtonTellesCunha If you have used the FormatSettings variable anywhere above the FillChar line - you have to Finalize(FormatSettings); before doing FillChar. In my example: I was assuming that FS is a local variable and FillChar will be the first action for it.Geronimo
P
9

below is what i use. there might be more efficient ways, but this works for me. in short, no, i don't know of any built-in delphi function that will convert a string-float containing commas to a float

{~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  safeFloat

  Strips many bad characters from a string and returns it as a double.
}
function safeFloat(sStringFloat : AnsiString) : double;
var
  dReturn : double;

begin
  sStringFloat := stringReplace(sStringFloat, '%', '', [rfIgnoreCase, rfReplaceAll]);
  sStringFloat := stringReplace(sStringFloat, '$', '', [rfIgnoreCase, rfReplaceAll]);
  sStringFloat := stringReplace(sStringFloat, ' ', '', [rfIgnoreCase, rfReplaceAll]);
  sStringFloat := stringReplace(sStringFloat, ',', '', [rfIgnoreCase, rfReplaceAll]);
  try
    dReturn := strToFloat(sStringFloat);
  except
    dReturn := 0;
  end;
  result := dReturn;

end;
Philippeville answered 25/4, 2009 at 3:26 Comment(2)
To make this work in other locales as well: Replace ',' in the last stringReplace line with ThousandSeparator.Immoderacy
You could also replace the dollar symbol with CurrencyString for other locales. tinyurl.com/cwvu37Amylum
S
5
function StrToFloat_Universal( pText : string ): Extended;
const
   EUROPEAN_ST = ',';
   AMERICAN_ST = '.';
var
  lformatSettings : TFormatSettings;
  lFinalValue     : string;
  lAmStDecimalPos : integer;
  lIndx           : Byte;
  lIsAmerican     : Boolean;
  lIsEuropean     : Boolean;

begin
  lIsAmerican := False;
  lIsEuropean := False;
  for lIndx := Length( pText ) - 1 downto 0 do
  begin
    if ( pText[ lIndx ] = AMERICAN_ST ) then
    begin
      lIsAmerican := True;
      pText := StringReplace( pText, ',', '', [ rfIgnoreCase, rfReplaceAll ]);  //get rid of thousand incidental separators
      Break;
    end;
    if ( pText[ lIndx ] = EUROPEAN_ST ) then
    begin
      lIsEuropean := True;
      pText := StringReplace( pText, '.', '', [ rfIgnoreCase, rfReplaceAll ]);  //get rid of thousand incidental separators
      Break;
    end;
  end;
  GetLocaleFormatSettings( LOCALE_SYSTEM_DEFAULT, lformatSettings );
  if ( lformatSettings.DecimalSeparator = EUROPEAN_ST ) then
  begin
    if lIsAmerican then
    begin
      lFinalValue := StringReplace( pText, '.', ',', [ rfIgnoreCase, rfReplaceAll ] );
    end;
  end;
  if ( lformatSettings.DecimalSeparator = AMERICAN_ST ) then
  begin
    if lIsEuropean then
    begin
      lFinalValue := StringReplace( pText, ',', '.', [ rfIgnoreCase, rfReplaceAll ] );
    end;
  end;
  pText  := lFinalValue;
  Result := StrToFloat( pText, lformatSettings );
end;
Sula answered 21/7, 2009 at 20:9 Comment(0)
O
4

Try: StrToFloat(StringReplace('3,232.00', ',', '') It should get rid of the commas before doing the conversion.

In C# / VB.NET I use would use something like decimal.convert("3,232.00", ",", "");

I know of no way to do the conversion without stripping out the extra characters. In fact, I have a special function in my library that strips out commas and currency symbols. So a actually call MyConverer.decimalConverter("$3,232.00");

Oilcloth answered 25/4, 2009 at 2:37 Comment(2)
That doesn't compile. StringReplace has a 4th parameter; 'Flags'Armour
Just put [] in flags parameter: StrToFloat(StringReplace('3,232.00', ',', '',[])Hardship
K
1

I use a function which is able to handle the ',' and the '.' as decimalseparator...:

function ConvertToFloat(aNr: String; aDefault:Integer): Extended;
var
  sNr, s3R, sWhole, sCent:String;
  eRC:Extended;
begin
  sNr:=ReplaceStr(sNr, ' ', '');

  if (Pos('.', sNr) > 0) or (Pos(',', sNr) > 0) then
  begin
    // Get 3rd character from right
    s3R:=LeftStr(RightStr(sNr, 3), 1);
    if s3R <> DecimalSeparator then
    begin
      if not IsNumber(s3R) then
      begin
        s3R := DecimalSeparator;
        sWhole := LeftSr(sNr, Length(sNr) - 3);
        sCent := (RightStr(sNr, 2);
        sNr := sWhole + DecimalSeparator + sCent;
      end
      else
        // there are no decimals... add ',00'
        sNr:=sNr + DecimalSeparator + '00';
    end;
    // DecimalSeparator is present; get rid of other symbols
    if (DecimalSeparator = '.') and (Pos(',', sNr) > 0) then sNr:=ReplaceStr(sNr, ',', '');
    if (DecimalSeparator = ',') and (Pos('.', sNr) > 0) then sNr:=ReplaceStr(sNr, '.', '');
  end;

  eRc := StrToFloat(sNr);
end;
Kavanaugh answered 26/9, 2012 at 13:12 Comment(0)
L
0

I had the same problem when my Users need to enter 'scientific' values such as "1,234.06mV". Here there is a comma, a multiplier (m=x0.001) and a unit (V). I created a 'wide' format converter routine to handle these situtations. Brian

Laine answered 25/4, 2009 at 6:6 Comment(0)
B
0

Myfunction:

function StrIsFloat2 (S: string;  out Res: Extended): Boolean;
var
  I, PosDecimal: Integer;
  Ch: Char;
  STrunc: string;
  liDots, liComma, J: Byte;
begin
  Result := False;
  if  S = ''
  then  Exit;
  liDots := 0;
  liComma := 0;
  for  I := 1 to Length(S)  do  begin
    Ch := S[I];
    if  Ch = FormatSettings.DecimalSeparator  then  begin
      Inc (liDots);
      if  liDots > 1  then  begin
        Exit;
      end;
    end
    else if  (Ch = '-') and (I > 1) then  begin
      Exit;
    end
    else if Ch = FormatSettings.ThousandSeparator then begin
      Inc (liComma);
    end
    else if not CharIsCipher(Ch) then  begin
      Exit;
    end;
  end;
  if liComma > 0 then begin
    PosDecimal := Pos (FormatSettings.DecimalSeparator, S);
    if PosDecimal = 0 then
      STrunc := S
    else
      STrunc := Copy (S, 1, PosDecimal-1);
    if STrunc[1] = '-' then
      Delete (S, 1, 1);
    if Length(STrunc) < ((liComma * 3) + 2) then
      Exit;
    J := 0;
    for I := Length(STrunc) downto 1 do begin
      Inc(J);
      if J mod 4 = 0 then
        if STrunc[I] <> FormatSettings.ThousandSeparator then
          Exit;
    end;
    S := ReplaceStr (S, FormatSettings.ThousandSeparator, '');
  end;
  try
    Res := StrToFloat (S);
    Result := True;
  except
    Result := False;
  end;
end;
Bernicebernie answered 23/7, 2017 at 21:6 Comment(0)
M
0

Using Foreach loop

 public static float[] ToFloatArray()
    {
     string pcords="200.812, 551.154, 232.145, 482.318, 272.497, 511.752";

      float[] spiltfloat = new float[pcords.Split(',').Length];
        int i = 0;
        foreach (string s in pcords.Split(','))
        {
           spiltfloat[i] = (float)(Convert.ToDouble(s));
            i++;
        }
        return spiltfloat;
    }
Maddalena answered 12/12, 2018 at 8:19 Comment(1)
You seem to have overlooked the Delphi tag in the question.Faria
M
0

using lemda Expression to convert string comma seprated to float array

public static float[] ToFloatArrayUsingLemda()
    {
        string pcords="200.812, 551.154, 232.145, 482.318, 272.497, 511.752";
        float[] spiltfloat = new float[pcords.Split(',').Length];

        string[] str = pcords.Split(',').Select(x => x.Trim()).ToArray();

        spiltfloat = Array.ConvertAll(str, float.Parse);
        return spiltfloat;
    }
Maddalena answered 12/12, 2018 at 8:23 Comment(1)
You seem to have overlooked the Delphi tag in the question.Faria
D
-1

procedure Edit1Exit(Sender: TObject);
begin
edit1.Text:=stringreplace(edit1.Text,'''','',[rfReplaceAll]);
if not IsValidDecimal( maskedit1.Text ) then
begin
showmessage('The Decimal entered -> '+edit1.Text+' <- is in the wrong format ');
edit1.SetFocus;
end;
end;

function IsValidDecimal(S:string):boolean;
VAR
FS: TFormatSettings;
DC: variant;
begin
//FS := TFormatSettings.Create('it-IT');
FS := TFormatSettings.Create('en-EN');
try
DC:=StrToFloat ( S, FS );
result:=true;
except
on e:exception do
result:=false;
end;

end;

Donatus answered 1/8, 2021 at 10:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.