2011-02-09 5 views
3

だから、私はシリアルポートを介しModBosから読み、読み値に次のようなものを取得しています:基本的に'+0020.8+0022.8-00.046-00.002-00.005-001.99+00.000+00.003';StrTok()やSscanf()のようなもの?

を、彼らは変化するかもしれないが、常に、プラスまたはマイナス記号が前に8本の浮動小数点の読みがあるでしょう文字の長さ。

浮動小数点型(または文字列型またはTSringList型の配列)の値を取得する最も効率的な方法は何ですか?

私は確信していませんが、これは時間がかかる可能性があるため、効率は優雅さを超える可能性があります。

+0

略語はいつもY2Kを思い出させる:Sundak、Mondak、Tuesdak、.... ;-) –

+4

あなたは[FastCodeプロジェクト](http://www.google.comに見たいと思うかもしれません/ search?sourceid = chrome&q = delphi + fastcode)探しているものと似たようなものが最適化されているかどうか確認してください。 –

+0

+ありがとうございます。役に立つリンクです – Mawg

答えて

8

私はこのようなものだろう:8つのfloat値が常に存在するため

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倍の固定された配列は十分です。私は文字列操作を最小限に保ちました。浮動小数点値ごとに1回だけ文字列がコピーされました。重要なのはTFormatSettingsで、それ以外の場合は、小数点記号がドット(私のような)ではないシステムでエラーが発生します。

ここでは例外処理はありませんが、浮動小数点数が8個の文字列が必要です。

+0

+1とその答え。 – Mawg

6

デルファイに移植されたVC++ sscanfをダウンロードして使用することができます。

+2

sscanfを呼びたい場合は、公式のWindowsシステムコンポーネントであるmsvcrt.dllを呼び出してください。 –

+1

2つの違い:私のsscanfはmsvcrt.dllに依存せず、%sはPCharではなくStringで動作します。 –

+2

OPがパフォーマンスを望んでいるので、私はmsvcrt.dllのものがここに示唆されたすべてのものを打ち負かすことを賭けて喜んでいる!! ;-) –

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. 
+0

+1おかげさまで – Mawg

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. 
+1

+1 3つの例すべてを1000回実行して、それぞれの例がそれぞれの結果に対して「WriteLn」を実行していることを確認してください。これは(ほとんどではありませんが)最速の解決策でした。ジョーン:103.90mSec、TheFox:104.32mSec、RRUZ:117.51mSec。 TheFoxによって提示されたソリューションは完全に正しいわけではありません。それは負の数の負の符号を見逃しました。 –

+1

@Lieven:エラーが修正されました –

+1

@Lieven:私はその機能を使い、すべての書き込みを取り除きました。そして、ジョーンは最も遅く、私は最も速いです。しかし、私はDelphi 7(FastMM 497)です。 –

2

、デルファイXEを使用して、新しいコンソールプロジェクトにコピーして貼り付けることができ、次の。 strtokのような

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. 
+0

+1以上のサービスは+1 ...ありがとう – Mawg