像StrTok()或Sscanf()这样的东西?

时间:2011-02-09 07:37:31

标签: delphi modbus

所以,我正在通过串口读取ModBos,并获得如下内容:'+0020.8+0022.8-00.046-00.002-00.005-001.99+00.000+00.003';

基本上,总会有8个浮点数读数,前面带有加号或减号,但它们的字符长度可能不同。

将值作为float数组(或string或TSringList数组)的最有效方法是什么?

我不确定,但这可能是时间关键,所以效率可能优于优雅。

5 个答案:

答案 0 :(得分:8)

我会做这样的事情:

type
  TFloatArray = array[0..7] of Double;

procedure ParseFloats(const aFloatStr: string;
  var aFloatArray: TFloatArray);
var
  lPos: Integer;
  lNextPos: Integer;
  lPosPositive: Integer;
  lPosNegative: Integer;
  i: Integer;
  lFormatSettings: TFormatSettings;
begin
  //do not forget formatsettings, or you will get problems with regional settings
  lFormatSettings.DecimalSeparator := '.';
  lFormatSettings.ThousandSeparator := ',';
  lPos := 1;
  for i := 0 to High(aFloatArray) do
  begin
    lPosPositive := PosEx('+', aFloatStr, lPos + 1);
    lPosNegative := PosEx('-', aFloatStr, lPos + 1);
    if lPosPositive = 0 then
      lNextPos := lPosNegative
    else if lPosNegative = 0 then
      lNextPos := lPosPositive
    else
      lNextPos := Min(lPosPositive, lPosNegative);
    if lNextPos = 0 then
      lNextPos := Length(aFloatStr) + 1;
    aFloatArray[i] := StrToFloat(Copy(aFloatStr, lPos, lNextPos - lPos), lFormatSettings);
    lPos := lNextPos;
  end;
end;

//call like this
var
  lFloats: TFloatArray;
begin
  ParseFloats('+0020.8+0022.8-00.046-00.002-00.005-001.99+00.000+00.003', lFloats);
end;

因为总有8个浮点值,所以8个双精度数的固定数组就足够了。我将字符串操作保持在最小值,每个浮点值只复制一次字符串。重要的是TFormatSettings,否则你会在小数分隔符不是点的系统上得到错误(就像我的)。

这里没有异常处理,我期望一个包含8个浮点值的字符串,仅此而已。

答案 1 :(得分:6)

您可以下载并使用移植到Delphi的VC ++ sscanf

答案 2 :(得分:4)

您可以使用TParser类来解析字符串。

检查此示例应用程序

program ParserDemo;

{$APPTYPE CONSOLE}

uses
  Classes,
  SysUtils;

procedure ProcessModBosOutPut(OutPut : string);
var
 StringStream  : TStringStream;
 Parser        : TParser;
 dValue        : Double;
 sValue        : string;
 FormatSettings: TFormatSettings;
begin
   FormatSettings.DecimalSeparator :='.';
   FormatSettings.ThousandSeparator:=',';
   //transform the output string to fit with the TParser logic
   OutPut:=StringReplace(OutPut,'+',' ',[rfReplaceAll]); //replace  '+' sign with a space
   OutPut:=StringReplace(OutPut,'-',' -',[rfReplaceAll]); //insert a empty space after of a '-' sign

   StringStream:=TStringStream.Create(OutPut);
   Parser:=TParser.Create(StringStream);
   try
        while Parser.Token <> toEOF do
        begin
           sValue:=Parser.TokenString; //get the string 
           dValue:=StrToFloat(sValue,FormatSettings); //convert the string
           //do something with the float value
           Writeln(FloatToStr(dValue));
           Parser.NextToken;
        end;
   finally
     Parser.Free;
     StringStream.Free;
   end;
end;

begin
  try
    ProcessModBosOutPut('+0020.8+0022.8-00.046-00.002-00.005-001.99+00.000+00.003');
  except
    on E:Exception do
      Writeln(E.Classname, ': ', E.Message);
  end;
  Readln;
end.

答案 3 :(得分:3)

program Project1;

{$APPTYPE CONSOLE}

uses
  SysUtils;

const
  CString = '+0020.8+0022.8-00.046-00.002-00.005-001.99+00.000+00.003';


var
  i,idx: Integer;
  tmpArray: Array[0..7] of Double;
  tmpString: ShortString;

begin
  DecimalSeparator := '.';

  idx := Low(tmpArray);
  tmpString := '';



  tmpString := CString[1];
  for i := 2 to Length(CString) do
  begin
    if CString[i] in ['+', '-']
    then begin
      TryStrToFloat(tmpString, tmpArray[idx]);
      Inc(idx);
      tmpString := CString[i];
    end
    else begin
      tmpString := tmpString + CString[i];
    end;
  end;
  TryStrToFloat(tmpString, tmpArray[idx]);


  for i := Low(tmpArray) to High(tmpArray) do
  begin
    Writeln(FloatToStr(tmpArray[i]));
  end;


  ReadLn;
end.

答案 4 :(得分:2)

对于有兴趣重复性能测试的人,可以使用Delphi XE将以下内容复制并粘贴到新的控制台项目中。

program Project1;

uses
  classes,
  sysutils,
  strutils,
  math;

{$APPTYPE CONSOLE}

type
  TFloatArray = array[0..7] of Double;

procedure ParseFloats_TheFox(const aFloatStr: string;
  var aFloatArray: TFloatArray);
var
  lPos: Integer;
  lNextPos: Integer;
  lPosPositive: Integer;
  lPosNegative: Integer;
  i: Integer;
  lFormatSettings: TFormatSettings;
begin
  //do not forget formatsettings, or you will get problems with regional settings
  lFormatSettings.DecimalSeparator := '.';
  lFormatSettings.ThousandSeparator := ',';
  lPos := 1;
  for i := 0 to High(aFloatArray) do
  begin
    lPosPositive := PosEx('+', aFloatStr, lPos + 1);
    lPosNegative := PosEx('-', aFloatStr, lPos + 1);
    if lPosPositive = 0 then
      lNextPos := lPosNegative
    else if lPosNegative = 0 then
      lNextPos := lPosPositive
    else
      lNextPos := Min(lPosPositive, lPosNegative);
    if lNextPos = 0 then
      lNextPos := Length(aFloatStr) + 1;
    //aFloatArray[i] := StrToFloat(Copy(aFloatStr, lPos, lNextPos - lPos), lFormatSettings);
    WriteLn(StrToFloat(Copy(aFloatStr, lPos, lNextPos - lPos), lFormatSettings));
    lPos := lNextPos;
  end;
end;

procedure ProcessModBosOutPut_RRUZ(OutPut : string);
var
 StringStream  : TStringStream;
 Parser        : TParser;
 dValue        : Double;
 sValue        : string;
 FormatSettings: TFormatSettings;
begin
   FormatSettings.DecimalSeparator :='.';
   FormatSettings.ThousandSeparator:=',';
   //transform the output string to fit with the TParser logic
   OutPut:=StringReplace(OutPut,'+',' ',[rfReplaceAll]); //replace  '+' sign with a space
   OutPut:=StringReplace(OutPut,'-',' -',[rfReplaceAll]); //insert a empty space after of a '-' sign

   StringStream:=TStringStream.Create(OutPut);
   Parser:=TParser.Create(StringStream);
   try
        while Parser.Token <> toEOF do
        begin
           sValue:=Parser.TokenString; //get the string
           dValue:=StrToFloat(sValue,FormatSettings); //convert the string
           //do something with the float value
           Writeln(FloatToStr(dValue));
           Parser.NextToken;
        end;
   finally
     Parser.Free;
     StringStream.Free;
   end;
end;


procedure Jorn(const floatstring: string);
var
  i,idx: Integer;
  tmpArray: Array[0..7] of Double;
  tmpString: ShortString;
begin
  DecimalSeparator := '.';

  idx := Low(tmpArray);
  tmpString := '';

  tmpString := floatstring[1];
  for i := 2 to Length(floatstring) do
  begin
    if floatstring[i] in ['+', '-']
    then begin
      writeln(strtofloat(tmpString));
      //TryStrToFloat(tmpString, tmpArray[idx]);
      Inc(idx);
      tmpString := floatstring[i];
    end
    else begin
      tmpString := tmpString + floatstring[i];
    end;
  end;
  //TryStrToFloat(tmpString, tmpArray[idx]);
  writeln(strtofloat(tmpString));
end;

//call like this
var
  lFloats: TFloatArray;
  I: Integer;
begin
  for I := 0 to 999 do
  begin
    ParseFloats_TheFox      ('+0020.8+0022.8-00.046-00.002-00.005-001.99+00.000+00.003', lFloats);
    WriteLn('The Fox');

    ProcessModBosOutPut_RRUZ('+0020.8+0022.8-00.046-00.002-00.005-001.99+00.000+00.003');
    WriteLn('RRUZ');

    Jorn                    ('+0020.8+0022.8-00.046-00.002-00.005-001.99+00.000+00.003');
    WriteLn('Jorn');
  end;

  readln;
end.