ThousandSeparator and convert from string lazarus / 62-General ---------------------------------------------------------------------- dseligo · 2022-11-17 17:48 Is there ready to use function like StrToFloat (also TryStrToFloat, StrToCurr, TryStrToCurr and similar) that works with ThousandSeparator? ---------------------------------------------------------------------- balazsszekely · 2022-11-17 18:31 Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i var  Str: String;  Dbl: Double;begin  Str := '1,000,000.00';  Str := StringReplace(Str, FormatSettings.ThousandSeparator, '', [rfReplaceAll]);  if TryStrToFloat(Str, Dbl) then    //...end; ---------------------------------------------------------------------- paweld · 2022-11-17 19:02 Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i var   Str: String;   Dbl: Double;   Fs: TFormatSettings; begin   Fs.ThousandSeparator := ',';   Fs.DecimalSeparator := '.';   Str := '1,000,000.00';   if TryStrToFloat(Str, Dbl, Fs) then     //...end; ---------------------------------------------------------------------- dseligo · 2022-11-17 20:15 Quote from: paweld on November 17, 2022, 08:02:55 pmCode: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i var   Str: String;   Dbl: Double;   Fs: TFormatSettings; begin   Fs.ThousandSeparator := ',';   Fs.DecimalSeparator := '.';   Str := '1,000,000.00';   if TryStrToFloat(Str, Dbl, Fs) then     //...end; Added this: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i     WriteLn('works: ' + FormatFloat('0.00', dbl))  else    WriteLn('didn''t convert'); And get: didn't convert It's because of this in TextToFloat function: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   //ThousandSeparator not allowed as by Delphi specs  if (FormatSettings.ThousandSeparator <> FormatSettings.DecimalSeparator) and     (Pos(FormatSettings.ThousandSeparator, S) <> 0) then    begin      Result := False;      Exit;    end; ---------------------------------------------------------------------- dseligo · 2022-11-17 20:16 Quote from: GetMem on November 17, 2022, 07:31:17 pmCode: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i var  Str: String;  Dbl: Double;begin  Str := '1,000,000.00';  Str := StringReplace(Str, FormatSettings.ThousandSeparator, '', [rfReplaceAll]);  if TryStrToFloat(Str, Dbl) then    //...end;  And if Str is '1,,,,000,000.00' or '1,0,0,0,0,0,0.00'? I want error in that case. So there is no ready to use function? ---------------------------------------------------------------------- balazsszekely · 2022-11-17 20:50 @dseligo QuoteAnd if Str is '1,,,,000,000.00' or '1,0,0,0,0,0,0.00'? I want error in that case. OK those are some extreme cases, but be aware that in some countries the following is a valid number: 100,00,00.00 This is why I suggested to remove the thousand separators first, then try to parse the remaining string. QuoteSo there is no ready to use function?AFAIK there is no ready to use function. PS: You should filter the input to prevent strings like "1,0,0,0,0,0,0.00'", or if your receive the strings from a third party application the documentation should specify the exact format. ---------------------------------------------------------------------- Bart · 2022-11-17 21:50 Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i function TryStrToFloatEx(S: String; FS: TFormatSettings; out Res: Double): Boolean;var  P, L: Integer;  Ch: Char;begin  Result := False;  if (Pos(FS.ThousandSeparator,S) = 0) then    Exit(TryStrToFloat(S, Res, FS));  P := Pos(FS.DecimalSeparator, S);  if (P = 0) then    P := Length(S) + 1;  begin    Dec(P);    L := 1;    while (P > 0) do    begin      Ch := S[P];      if ((L mod 4) = 0) then      begin        if (Ch <> FS.ThousandSeparator) then          Exit(False);      end    else      begin        if (Ch = FS.ThousandSeparator) then          Exit(False);      end;      Dec(P);      Inc(L);    end;    S := StringReplace(S, FS.ThousandSeparator, '', [rfReplaceAll]);    Result := TryStrToFloat(S, Res, FS);  end;end; If the string contains a ThousandSeparator, then it will only parse if the TS is found at places it should be, which is defined as the thousands should be grouped as 3 digits: 1,234,567.0: OK 1,23,456.0: not OK. Can of course be rewritten to perform much faster... Bart ---------------------------------------------------------------------- dseligo · 2022-11-17 21:52 Quote from: GetMem on November 17, 2022, 09:50:05 pm@dseligo QuoteAnd if Str is '1,,,,000,000.00' or '1,0,0,0,0,0,0.00'? I want error in that case. OK those are some extreme cases, but be aware that in some countries the following is a valid number: 100,00,00.00 This is why I suggested to remove the thousand separators first, then try to parse the remaining string. Yes, I think that in India they use something like this. QuoteQuoteSo there is no ready to use function?AFAIK there is no ready to use function. PS: You should filter the input to prevent strings like "1,0,0,0,0,0,0.00'", or if your receive the strings from a third party application the documentation should specify the exact format. I'll make my function then to check if thousand separators are in the right places. I just wanted to know if there is already made function to save time and I because will probably miss some checks. ---------------------------------------------------------------------- dseligo · 2022-11-17 21:54 Quote from: Bart on November 17, 2022, 10:50:45 pmIf the string contains a ThousandSeparator, then it will only parse if the TS is found at places it should be, which is defined as the thousands should be grouped as 3 digits: 1,234,567.0: OK 1,23,456.0: not OK. Can of course be rewritten to perform much faster... Bart Thank you for code, I'll check it. Speed is not of importance to me here (I am checking input from keyboard). ---------------------------------------------------------------------- dseligo · 2022-11-17 22:40 Quote from: Bart on November 17, 2022, 10:50:45 pmCode: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i function TryStrToFloatEx(S: String; FS: TFormatSettings; out Res: Double): Boolean;var  P, L: Integer;  Ch: Char;begin  Result := False;  if (Pos(FS.ThousandSeparator,S) = 0) then    Exit(TryStrToFloat(S, Res, FS));  P := Pos(FS.DecimalSeparator, S);  if (P = 0) then    P := Length(S) + 1;  begin    Dec(P);    L := 1;    while (P > 0) do    begin      Ch := S[P];      if ((L mod 4) = 0) then      begin        if (Ch <> FS.ThousandSeparator) then          Exit(False);      end    else      begin        if (Ch = FS.ThousandSeparator) then          Exit(False);      end;      Dec(P);      Inc(L);    end;    S := StringReplace(S, FS.ThousandSeparator, '', [rfReplaceAll]);    Result := TryStrToFloat(S, Res, FS);  end;end; If the string contains a ThousandSeparator, then it will only parse if the TS is found at places it should be, which is defined as the thousands should be grouped as 3 digits: 1,234,567.0: OK 1,23,456.0: not OK. Can of course be rewritten to perform much faster... Bart OK, I tried it and it's fine except I changed line 20 to: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i         if (Ch <> FS.ThousandSeparator) or (P = 1) then I did it because otherwise number ',123' was OK. Is there some meaning for begin/end pair in the lines 12/33? Was there some 'if' or something? ---------------------------------------------------------------------- Thaddy · 2022-11-18 07:45 Bart may have put those in for readability. There are more places. This is the same code without unnecessary begin ends:Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i function TryStrToFloatEx(S: String; FS: TFormatSettings; out Res: Double): Boolean;var  P, L: Integer;  Ch: Char;begin  Result := False;  if (Pos(FS.ThousandSeparator,S) = 0) then    Exit(TryStrToFloat(S, Res, FS));  P := Pos(FS.DecimalSeparator, S);  if (P = 0) then    P := Length(S) + 1;  Dec(P);  L := 1;  while (P > 0) do  begin    Ch := S[P];    if ((L mod 4) = 0) then      if (Ch <> FS.ThousandSeparator) then        Exit(False)    else      if (Ch = FS.ThousandSeparator) then        Exit(False);    Dec(P);    Inc(L);  end;  S := StringReplace(S, FS.ThousandSeparator, '', [rfReplaceAll]);  Result := TryStrToFloat(S, Res, FS);end;It is a matter of taste. I also use extra begin/ends for some examples, but not in my production code. It can sometimes clarify the meaning of the code somewhat. ---------------------------------------------------------------------- Zvoni · 2022-11-18 08:09 Quote from: dseligo on November 17, 2022, 10:54:40 pmThank you for code, I'll check it. Speed is not of importance to me here (I am checking input from keyboard). Then don't allow a ThousandSeparator to be entered. Easy as that. There should be thousands of examples how to validate User-Input. The way i do it, if user has to enter Floats: Only numbers/Digits, Backspace, delete allowed (depending on the usecase i allow Tab and CR additionally, but those two are usually to jump out of the TEdit and/or to trigger an action) Exactly one or none decimal separator No thousandseparator allowed at all If user gets smart, and thinks "Ha, i'm going to outsmart the idiot, and copy/paste my value with thousandseparators" --> OnChange-Event and filter the crap out ---------------------------------------------------------------------- MarkMLl · 2022-11-18 08:13 Quote from: dseligo on November 17, 2022, 10:52:04 pmI'll make my function then to check if thousand separators are in the right places. I just wanted to know if there is already made function to save time and I because will probably miss some checks. I'd suggest that it also needs a sanity check for the relative positions of the thousands and dismal separators, for the case where numbers originating in one locale e.g. 1.000,0 are being parsed in a different one that expects e.g. 1,000.0 MarkMLl ---------------------------------------------------------------------- dseligo · 2022-11-18 17:05 Quote from: Thaddy on November 18, 2022, 08:45:30 amBart may have put those in for readability. There are more places. This is the same code without unnecessary begin ends:Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i function TryStrToFloatEx(S: String; FS: TFormatSettings; out Res: Double): Boolean;var  P, L: Integer;  Ch: Char;begin  Result := False;  if (Pos(FS.ThousandSeparator,S) = 0) then    Exit(TryStrToFloat(S, Res, FS));  P := Pos(FS.DecimalSeparator, S);  if (P = 0) then    P := Length(S) + 1;  Dec(P);  L := 1;  while (P > 0) do  begin    Ch := S[P];    if ((L mod 4) = 0) then      if (Ch <> FS.ThousandSeparator) then        Exit(False)    else      if (Ch = FS.ThousandSeparator) then        Exit(False);    Dec(P);    Inc(L);  end;  S := StringReplace(S, FS.ThousandSeparator, '', [rfReplaceAll]);  Result := TryStrToFloat(S, Res, FS);end;It is a matter of taste. I also use extra begin/ends for some examples, but not in my production code. It can sometimes clarify the meaning of the code somewhat. You got it wrong. You need lines 18 and 19 between begin/end block. ---------------------------------------------------------------------- Thaddy · 2022-11-18 17:19 Quote from: dseligo on November 18, 2022, 06:05:58 pmYou got it wrong. You need lines 18 and 19 between begin/end block.Nope. Nothing wrong, here's a somewhat embellished explanation:Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i       if ((L mod 4) = 0) then      // begin        if (Ch <> FS.ThousandSeparator) then          Exit(False) //;      // end      else      // begin        if (Ch = FS.ThousandSeparator) then        Exit(False);      // end; Check it out for yourself. Removing the explicit block notation does not change the meaning of the code... All blocks are in effect single expressions, so begin/end can be eliminated. Explicit blocks are only necessary with multiple expressions. A common misunderstanding, so don't worry. It does not hurt. ---------------------------------------------------------------------- dseligo · 2022-11-18 17:31 Quote from: Thaddy on November 18, 2022, 06:19:09 pmQuote from: dseligo on November 18, 2022, 06:05:58 pmYou got it wrong. You need lines 18 and 19 between begin/end block.Nope. Nothing wrong, here's a somewhat embellished explanation:Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i       if ((L mod 4) = 0) then      // begin        if (Ch <> FS.ThousandSeparator) then          Exit(False) //;      // end      else      // begin        if (Ch = FS.ThousandSeparator) then        Exit(False);      // end; Check it out for yourself. Removing the explicit block notation does not change the meaning of the code... All blocks are in effect single expressions, so begin/end can be eliminated. I don't have to check it, I clearly see your version is wrong. In Bart's code 'else' is part of this 'if': 'if ((L mod 4) = 0) then', and in your code 'else' is part of this 'if': if (Ch <> FS.ThousandSeparator) then. ---------------------------------------------------------------------- Thaddy · 2022-11-18 17:37 Again: NO The above code is Bart's code... with just the superflous begin/end removed. You misread the program flow. It is rather basic and your assumption is plain wrong. Trying to help here... ---------------------------------------------------------------------- wp · 2022-11-18 17:49 Thaddy, you're wrong: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program Project1; uses  SysUtils; const  ThousandSeparator: Char = '.'; function Test1(L: Integer; ch: Char): Boolean;begin  Result := true;  if ((L mod 4) = 0) then    if (Ch <> ThousandSeparator) then    Exit(False)  else    if (Ch = ThousandSeparator) then      Exit(False);end; function Test2(L: Integer; ch: Char): Boolean;begin  Result := true;  if ((L mod 4) = 0) then  begin    if (Ch <> ThousandSeparator) then      Exit(False);  end  else  begin    if (Ch = ThousandSeparator) then      Exit(False);  end;end; begin  WriteLn(BoolToStr(Test1(1, '0'), true));  WriteLn(BoolToStr(Test2(1, '0'), true));  WriteLn;  WriteLn(BoolToStr(Test1(4, '0'), true));  WriteLn(BoolToStr(Test2(4, '0'), true));  WriteLn;  WriteLn(BoolToStr(Test1(1, '.'), true));  WriteLn(BoolToStr(Test2(1, '.'), true));  WriteLn;  WriteLn(BoolToStr(Test1(4, '.'), true));  WriteLn(BoolToStr(Test2(4, '.'), true));  WriteLn;   ReadLn;end. Output: Each block of two lines should display the same boolean results if Test1 (Bart's code) and Test2 (your code) were equivalent: Code: [Select]True True False False True False False True ---------------------------------------------------------------------- dseligo · 2022-11-18 17:50 Quote from: Thaddy on November 18, 2022, 06:37:11 pmAgain: NO The above code is Bart's code... with just the superflous begin/end removed. You misread the program flow. It is rather basic and your assumption is plain wrong. Trying to help here... Sure. Just try to convert '1.234' with your code (or '1,234' if comma is your thousand separator). ---------------------------------------------------------------------- dseligo · 2022-11-18 18:16 I found a few more problems when testing Bart's code from reply #6. Apart from additional check that thousand separator is not first sign, here are other problems: - need to trim string: original TryStrTo... trims string and if there are spaces in front then thousand separator checks doesn't work correct. - check for exponent sign if there is no decimal separator (I don't use this, but just for completeness) - check for minus This is corrected code: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i function TryStrToFloatEx(S: String; FS: TFormatSettings; out Res: Double): Boolean;var  P, L, MinusPos: Integer;  Ch: Char;begin  Result := False;  if Pos(FS.ThousandSeparator, S) = 0 then    Exit(TryStrToFloat(S, Res, FS));  S := Trim(S);  P := Pos(FS.DecimalSeparator, S);  if P = 0 then  begin    P := Pos('e', LowerCase(S));    If P = 0 then      P := Length(S) + 1;  end;  MinusPos := Pos('-', S);  If (MinusPos > 1) and (MinusPos < P) then // minus can be just after 'e'    Exit;  If MinusPos > 1 then    MinusPos := 0;  Dec(P);  L := 1;  while P > MinusPos do  begin    Ch := S[P];  if (L mod 4) = 0 then    begin      if (Ch <> FS.ThousandSeparator) or (P = (MinusPos + 1)) then        Exit(False);    end    else      if Ch = FS.ThousandSeparator then        Exit(False);    Dec(P);    Inc(L);  end;  S := StringReplace(S, FS.ThousandSeparator, '', [rfReplaceAll]);  Result := TryStrToFloat(S, Res, FS);end; Here is currency version: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i function TryStrToCurrEx(S: String; FS: TFormatSettings; out Res: Currency): Boolean;var  P, L, MinusPos: Integer;  Ch: Char;begin  Result := False;  if Pos(FS.ThousandSeparator, S) = 0 then    Exit(TryStrToCurr(S, Res, FS));  S := Trim(S);  P := Pos(FS.DecimalSeparator, S);  if P = 0 then  begin    P := Pos('e', LowerCase(S));    If P = 0 then      P := Length(S) + 1;  end;  MinusPos := Pos('-', S);  If (MinusPos > 1) and (MinusPos < P) then // minus can be just after 'e'    Exit;  If MinusPos > 1 then    MinusPos := 0;  Dec(P);  L := 1;  while P > MinusPos do  begin    Ch := S[P];  if (L mod 4) = 0 then    begin      if (Ch <> FS.ThousandSeparator) or (P = (MinusPos + 1)) then        Exit(False);    end    else      if Ch = FS.ThousandSeparator then        Exit(False);    Dec(P);    Inc(L);  end;  S := StringReplace(S, FS.ThousandSeparator, '', [rfReplaceAll]);  Result := TryStrToCurr(S, Res, FS);end; ---------------------------------------------------------------------- BobDog · 2022-11-18 18:29 For a simple console input. (Simple program) Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i  vars:ansis tring='';d:char;code:word;number:double; beginwriteln('Enter your number');repeatread(d);if (d = '.')  and (pos('.',s)=0) then s:=s+d;if d in['0'..'9'] then s:=s+d;until (d=char(13)); val(s,number,code);writeln('String = ',s,'   --- Number = ',number);writeln('Press return to end . . .');readln;readln; end. ---------------------------------------------------------------------- Bart · 2022-11-18 20:31 Quote from: dseligo on November 18, 2022, 07:16:16 pmI found a few more problems when testing Bart's code from reply #6. Apart from additional check that thousand separator is not first sign, here are other problems: - need to trim string: original TryStrTo... trims string and if there are spaces in front then thousand separator checks doesn't work correct. - check for exponent sign if there is no decimal separator (I don't use this, but just for completeness) - check for minus It was meant as a starting point. I would think that all this issues can be resolve if you find the first digit and in the while loop replace "while (P > 0)" with "while (P > FirstDigit)". This should properly reject ',123' and allow '+1,234.00'. Bart ---------------------------------------------------------------------- dseligo · 2022-11-18 20:44 Quote from: Bart on November 18, 2022, 09:31:03 pmQuote from: dseligo on November 18, 2022, 07:16:16 pmI found a few more problems when testing Bart's code from reply #6. Apart from additional check that thousand separator is not first sign, here are other problems: - need to trim string: original TryStrTo... trims string and if there are spaces in front then thousand separator checks doesn't work correct. - check for exponent sign if there is no decimal separator (I don't use this, but just for completeness) - check for minus It was meant as a starting point. I would think that all this issues can be resolve if you find the first digit and in the while loop replace "while (P > 0)" with "while (P > FirstDigit)". This should properly reject ',123' and allow '+1,234.00'. Bart I know, I didn't mean to criticize you. I agree it would be simpler, but 'e' still need to be addressed if there is no decimal sign. I'll rework it to be simpler when I found some time, it's working OK for me now. P.S.: And it also needs checking for thousand separator after decimal sign/exponent sign. ---------------------------------------------------------------------- Bart · 2022-11-18 20:52 Would you actually allow thosandseparator in scientific format: 1,234.0E+10 is a bit horrible. My code doesn't handle this at all, but I would reject that, but that's just my personal feeling. Bart ---------------------------------------------------------------------- Bart · 2022-11-18 21:10 Quote from: dseligo on November 18, 2022, 09:44:20 pmI know, I didn't mean to criticize you. I know. This seems to handle '-1,234.0E+12'. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i function TryStrToFloatEx(S: String; FS: TFormatSettings; out Res: Double): Boolean;var  P, L, FirstDigit: Integer;  Ch: Char;begin  Result := False;  if (Pos(FS.ThousandSeparator,S) = 0) then    Exit(TryStrToFloat(S, Res, FS));  P := Pos(FS.DecimalSeparator, S);  if (P = 0) then  begin    P := Pos('E', UpperCase(S));  //123E10    if (P = 0) then      P := Length(S) + 1;  end;  FirstDigit := 1;  for L := 1 to Length(S) do  begin    if S[L] in ['0'..'9'] then    begin    FirstDigit := L;      Break;    end;  end;  begin    Dec(P);    L := 1;    while (P > FirstDigit) do    begin      Ch := S[P];      if ((L mod 4) = 0) then      begin        if (Ch <> FS.ThousandSeparator) then          Exit(False);      end      else      begin        if (Ch = FS.ThousandSeparator) then          Exit(False);      end;      Dec(P);      Inc(L);    end;    S := StringReplace(S, FS.ThousandSeparator, '', [rfReplaceAll]);    Result := TryStrToFloat(S, Res, FS);  end;end; Quote from: dseligo on November 18, 2022, 09:44:20 pmP.S.: And it also needs checking for thousand separator after decimal sign/exponent sign. You mean you want to allow '1,234.5E+1,234'?? If so, the piece of code that checks for sanity of TS in a given string of only digits should be extracted so that it can be re-used. Then extract the digits before the 'E' and the digits behind and sanitise them. Bart ---------------------------------------------------------------------- dseligo · 2022-11-18 21:56 Quote from: Bart on November 18, 2022, 10:10:25 pmYou mean you want to allow '1,234.5E+1,234'?? No, I want to return 'false' if there is thousand separator after decimal sign. ---------------------------------------------------------------------- Bart · 2022-11-18 22:36 Quote from: dseligo on November 18, 2022, 10:56:32 pmNo, I want to return 'false' if there is thousand separator after decimal sign. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i function TryStrToFloatEx(S: String; FS: TFormatSettings; out Res: Double): Boolean;var  P, L, FirstDigit: Integer;  Ch: Char;begin  Result := False;  if (Pos(FS.ThousandSeparator,S) = 0) then    Exit(TryStrToFloat(S, Res, FS));  P := Pos(FS.DecimalSeparator, S);  if (P = 0) then  begin    P := Pos('E', UpperCase(S));  //123E10    if (P = 0) then      P := Length(S) + 1;  end;  //No TS allowed after DS or E  if (Pos(FS.ThousandSeparator, S, P-1) > 0) then  //needs fpc 3.2.2 or higher    Exit;  FirstDigit := 1;  for L := 1 to Length(S) do  begin    if S[L] in ['0'..'9'] then    begin      FirstDigit := L;      Break;    end;  end;  begin    Dec(P);    L := 1;    while (P > FirstDigit) do    begin      Ch := S[P];      if ((L mod 4) = 0) then      begin        if (Ch <> FS.ThousandSeparator) then          Exit(False);      end      else      begin        if (Ch = FS.ThousandSeparator) then          Exit(False);      end;      Dec(P);      Inc(L);    end;    S := StringReplace(S, FS.ThousandSeparator, '', [rfReplaceAll]);    Result := TryStrToFloat(S, Res, FS);  end;end; Bart ---------------------------------------------------------------------- jamie · 2022-11-18 23:02 I've never seen such confusion Maybe it's bar night? Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.Button2Click(Sender: TObject);Var  S:String;begin  S := '1245,656.000+13,45';  If (Pos('.',S)<>0) and (Pos(',',Copy(S,Pos('.',S),Length(S))) <> 0) Then Beep;end;                                                      This detects if there is a common at the end after the '.'  it also assumes a false state if there is no '.' in the string to start with but that can be removed so it always detects a ',' in case there is no '.' in the string.  Did I miss something here ? ---------------------------------------------------------------------- ASerge · 2022-11-19 12:25 Quote from: jamie on November 19, 2022, 12:02:08 am Did I miss something here ? Read the topic from the beginning and you will find '1,,,,000,000.00' or '1,0,0,0,0,0,0.00'. ---------------------------------------------------------------------- ASerge · 2022-11-19 13:57 Bart's idea with the test: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i {$APPTYPE CONSOLE}{$MODE OBJFPC}{$LONGSTRINGS ON} uses SysUtils, StrUtils; // Extracted to exclude stack clutteringfunction TryStrToFloatIgnoreThousandSeparator(const S: string;  const FS: TFormatSettings; out Value: ValReal): Boolean;begin  Result := TryStrToFloat(DelChars(S, FS.ThousandSeparator), Value, FS);end; function TryStrToFloatEx(const S: string; const FS: TFormatSettings;  out Value: ValReal): Boolean;const  CDigits: array of Char = ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9');var  IndexOfSeparator: SizeInt;  IndexOfFirstDigit: SizeInt;  CountOfChars: SizeInt;  iChar: SizeInt;begin  Result := False;  if Pos(FS.ThousandSeparator, S) = 0 then    Exit(TryStrToFloat(S, Value, FS));  IndexOfSeparator := Pos(FS.DecimalSeparator, S) - 1;  if IndexOfSeparator < 0 then    IndexOfSeparator := S.LastIndexOfAny(['e', 'E']);  if IndexOfSeparator < 0 then    IndexOfSeparator := Length(S);  //No TS allowed after DS or E  if Pos(FS.ThousandSeparator, S, IndexOfSeparator) > 0 then  //needs fpc 3.2.2 or higher    Exit;  IndexOfFirstDigit := S.IndexOfAny(CDigits);  if IndexOfFirstDigit < 0 then    Exit;  CountOfChars := 1;  for iChar := IndexOfSeparator downto IndexOfFirstDigit + 1 do  begin    // (N mod 4) = 0 equal (N and 3) = 0, but faster    if ((CountOfChars and 3) = 0) <> (S[iChar] = FS.ThousandSeparator) then      Exit;    Inc(CountOfChars);  end;  Result := TryStrToFloatIgnoreThousandSeparator(S, FS, Value);end; procedure Test(const S: string);var  FS: TFormatSettings;  Value: ValReal;begin  FS := DefaultFormatSettings;  FS.DecimalSeparator := '#';  FS.ThousandSeparator := '_';  Write(S);  if TryStrToFloatEx(S, FS, Value) then    Writeln(' - OK, value is ', Value:0:3)  else    Writeln(' - Fail');end; begin  Writeln('ThousandSeparator = _, DecimalSeparator = #');  Writeln;  Test('12.15');  Test('2___000_000#123');  Test('3_456#123');  Test('4_0_0_0_0_0_0#123');  Test('5_000#123_4');  Test('6#000#123');  Test('_456#123');  Test('7_000e2#123');  Test('8_000#123e2');  Readln;end. ---------------------------------------------------------------------- jamie · 2022-11-19 14:09 QuoteQuote from: Bart on November 18, 2022, 10:10:25 pm You mean you want to allow '1,234.5E+1,234'?? No, I want to return 'false' if there is thousand separator after decimal sign. ^^^^^^^^^^^^^^^ ---------------------------------------------------------------------- Bart · 2022-11-19 22:09 B.t.w.: I rembered doing something similar in the past. My FsiSillyStuff unit has a TryParseFloat function that allows for multiple separators and can accept thousandseparators. It was designed to be able to parse a file of floats, which could have different values for DecimalSeparator, the allowing of ThousandSeparator was just for fun. It has overloads for Single, Double and Extended. If you set AcceptedSeparators to ['.',','] it will parse both '1.23' as well as '1,23'. If you allow more than one separator and AllowThousandSeparator is True, then the last separator in the string is used as DecimalSeparator, the one before that as ThousandSeparator. So, it will parse '1,234.456' as 1234.456 and '1.234,456' also as 1234.456. Bart ---------------------------------------------------------------------- Bart · 2022-11-23 18:40 Fixed some issues (it accepted '+,123' and '$1,234') refactored and made single, double and extended versions. Got bored and made the same for integer conversions. Can be found in my FsiConv unit. Hope it's usefull for someone. Bart