【问题标题】:Convert string with commas to float将带逗号的字符串转换为浮点数
【发布时间】:2009-04-25 02:33:02
【问题描述】:

是否有内置的 Delphi 函数可以将字符串(例如 '3,232.00')转换为浮点数? StrToFloat 由于逗号而引发异常。还是先去掉逗号再做 StrToFloat 的唯一方法?

谢谢。

【问题讨论】:

  • 在逗号用作小数点的语言环境中是否有任何要求?例如,在欧洲的任何地方?

标签: delphi regional


【解决方案1】:

你知道吗,那个'.'是小数分隔符,',' 是千位分隔符(总是)? 如果是这样,那么您应该填写 TFormatSettings 记录并将其传递给 StrToFloat。

FillChar(FS, SizeOf(FS), 0);
... // filling other fields
FS.ThousandSeparator := ',';
FS.DecimalSeparator := '.';
V := StrToFloat(S, FS);

【讨论】:

  • 假设您使用的是 Delphi 7 或更高版本,否则 formatsettings 参数不可用,并且 StrToFloat 很乐意忽略您设置的任何千位分隔符。
  • FillChar(FS, SizeOf(FS), 0); 真的有必要吗?它似乎也可以在没有(Delphi XE2)的情况下工作。
  • @user1580348 是的,这是必要的。它可以工作,但只能通过巧合。也就是说:要么填充所有字段(并且在下一个 Delphi 版本中不添加新字段),要么 StrToFloat 不使用 FS 中的垃圾。由于您几乎无法控制 Delphi RTL - 您应该将未使用的字段归零。
  • 这在 XE6 上不起作用。 StrToFloat 的帮助文件明确指出,“字符串中不允许使用千位分隔符和货币符号”。包括格式设置似乎对此没有任何影响。
  • D7 中的 StrToFloat() 不适用于千位分隔符(逗号、空格、句点(法语)等),无论传入的 TFormatSettings 是什么。它们需要先被剥离(参见StringReplace 在另一个答案中)。我很惊讶这被标记为解决方案。它是否适用于其他版本的其他人? StrToFloat() 确实使用传入的 TFormatSettings 小数分隔符,但这不是这里的问题。
【解决方案2】:

下面是我使用的。可能有更有效的方法,但这对我有用。简而言之,不,我不知道有任何内置的 delphi 函数可以将包含逗号的字符串浮点数转换为浮点数

{~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  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;

【讨论】:

  • 为了在其他语言环境中也能正常工作:替换最后一个字符串中的 ',' 将行替换为 ThousandSeparator。
  • 对于其他语言环境,您还可以将美元符号替换为 CurrencyString。 tinyurl.com/cwvu37
【解决方案3】:

试试:StrToFloat(StringReplace('3,232.00', ',', '') 它应该在进行转换之前去掉逗号。

在 C#/VB.NET 中,我会使用 decimal.convert("3,232.00", ",", ""); 之类的东西

我知道在不去除多余字符的情况下无法进行转换。事实上,我的库中有一个特殊的函数可以去掉逗号和货币符号。所以实际调用MyConverer.decimalConverter("$3,232.00");

【讨论】:

  • 那不编译。 StringReplace 有第四个参数; '标志'
  • 只需将 [] 放入 flags 参数中: StrToFloat(StringReplace('3,232.00', ',', '',[])
【解决方案4】:
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;

【讨论】:

    【解决方案5】:

    我使用了一个能够处理 ',' 和 '.' 的函数作为十进制分隔符...:

    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;
    

    【讨论】:

      【解决方案6】:

      当我的用户需要输入“1,234.06mV”等“科学”值时,我遇到了同样的问题。这里有一个逗号、一个乘数 (m=x0.001) 和一个单位 (V)。我创建了一个“宽”格式转换器例程来处理这些情况。 布赖恩

      【讨论】:

        【解决方案7】:

        我的功能:

        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;
        

        【讨论】:

          【解决方案8】:

          使用 Foreach 循环

           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;
              }
          

          【讨论】:

          • 您似乎忽略了问题中的Delphi标签。
          【解决方案9】:

          使用lemda表达式将逗号分隔的字符串转换为浮点数组

          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;
              }
          

          【讨论】:

          • 你似乎忽略了问题中的Delphi标签。
          【解决方案10】:

          procedure Edit1Exit(Sender: TObject);
          开始
          edit1.Text:=stringreplace(edit1.Text,'''','',[rfReplaceAll]);
          如果不是 IsValidDecimal(maskedit1.Text) 那么
          开始
          showmessage('输入的十进制数 -> '+edit1.Text+' edit1.SetFocus;
          结束;
          结束;

          函数 IsValidDecimal(S:string):boolean;
          VAR
          FS:TFormatSettings;
          DC:变体;
          开始
          //FS := TFormatSettings.Create('it-IT');
          FS := TFormatSettings.Create('en-EN');
          试试
          DC:=StrToFloat ( S, FS );
          结果:=真;
          除了
          在 e:exception do
          结果:=假;
          结束;

          结束;

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2020-04-21
            • 1970-01-01
            • 2022-06-15
            • 1970-01-01
            相关资源
            最近更新 更多