2012-03-22 79 views
4

我有一個指定結構的文本文件,即(對於每行):char,space,char,space,double value,endline。例如在FreePascal中讀取文件

q w 1.23 
e r 4.56 
t y 7.89 

在Free Pascal中「提取」這些值的正確方法是什麼?

回答

2

您可以使用TStringList類加載文件,並使用DelimitedText屬性拆分另一個TStringList上的值,然後將這些值存儲在記錄中。

檢查該樣本

{$mode objfpc}{$H+} 

uses 
    Classes, SysUtils; 

{$R *.res} 

type 
    TData=record 
    Val1: Char; 
    Val2: Char; 
    Val3: Double; 
    end; 

procedure ProcessFile; 
var 
    LFile : TStringList; 
    Line : TStringList; 
    i  : Integer; 
    LData : TData; 
    LFormat: TFormatSettings; 
begin 
    //set the propert format for the foat values 
    LFormat:=DefaultFormatSettings; 
    LFormat.DecimalSeparator:='.'; 

    LFile:=TStringList.Create; 
    Line :=TStringList.Create; 
    try 
    //load the file 
    LFile.LoadFromFile('C:\Bar\Foo\Data.txt'); 
    Line.Delimiter:=' '; 
    for i:=0 to LFile.Count-1 do 
    begin 
     //read the line and split the result 
     Line.DelimitedText:=LFile[i]; 
     //some basic check 
     if Line.Count <> 3 then raise Exception.Create('Wrong data length'); 

     //you can add additional check here  
     LData.Val1:=Line[0][3]; 
     LData.Val2:=Line[1][4]; 
     LData.Val3:=StrToFloat(Line[2],LFormat); 

     //do something with the data 
     WriteLn(LData.Val1); 
     WriteLn(LData.Val2); 
     WriteLn(LData.Val3); 
    end; 
    finally 
    Line.Free; 
    LFile.Free; 
    end; 
end; 

begin 
try 
    ProcessFile; 
except on E:Exception do Writeln(E.Classname, ':', E.Message); 
end; 
Writeln('Press Enter to exit'); 
Readln; 
end. 
4

FreePascal的在SysUtils單元的功能sscanf的(你可能知道,如果從其他語言。)

我修改RRUZ的例子來說明如何使用它。

uses SysUtils; 

type 
    TData=object 
    Val1 , 
    Val2 : String; 
    Val3 : Double; 
    end; 

procedure ProcessFile(aFileName:String); 
var 
    F  : Text; 
    LData : TData; 
    Line : String; 
begin 
    DecimalSeparator:='.'; 
    AssignFile(F,aFileName); 
    Reset(F); 
    while not eof(F) do 
    begin 
    ReadLn(F,Line); 
    SScanf(Line,'%s %s %f',[@LData.Val1,@LData.Val2,@LData.Val3]); 

    //do something with the data 
    WriteLn(LData.Val1); 
    WriteLn(LData.Val2); 
    WriteLn(LData.Val3); 
    end; 
end; 

begin 
    ProcessFile('C:\Bar\Foo\Data.txt'); 
    Writeln('Press Enter to exit'); 
    Readln; 
end. 
+1

使用不安全的構造。 (例如,如果字符串不是shortstring,則編譯但失敗)。不會推薦這個(對於初學者或專家) – 2012-11-14 18:48:07

+1

@MarcovandeVoort您能否提供使用SScanF的正確方法? – SOUser 2014-09-10 22:25:56

1

比方說,我們有興趣閱讀文件,切換後命令行參數提供,包含替代配重的角色。

program WeightFileRead; 
uses SysUtils, StrUtils; 
var 
    MyFile : TextFile; 
    FirstChar, SecondChar, DummyChar : Char; 
    Weight : Double; 
begin 
    if GetCmdLineArg ('editweights', StdSwitchChars) = '' 
    then begin 
     WriteLn ('Syntax: WeightFileRead -editweights filename'); exit 
    end; 
    AssignFile (MyFile, GetCmdLineArg ('editweights', StdSwitchChars)); 
    Reset (MyFile); 
    try 
     while not EOF (MyFile) do 
     begin 
     ReadLn (MyFile, FirstChar, DummyChar, SecondChar, Weight); 
     WriteLn ('A: ', FirstChar, '; B: ', SecondChar, '; W: ', Weight:0:1); 
     end 
    finally 
     CloseFile (MyFile) 
    end 
end. 

在更一般的設置中,當第2項可以是更長的串,我們可以使用ExtractWord在一個字符串發現n個空格分隔單詞,(或ExtractSubstr所述治療若干空格一起作爲引入空詞),並將第三個轉換爲數字。

program WeightFileRead2; 
uses SysUtils, StrUtils; 
var 
    MyFile : TextFile; 
    FileLine : String; 
begin 
    if GetCmdLineArg ('editweights', StdSwitchChars) = '' 
    then begin 
     WriteLn ('Syntax: WeightFileRead -editweights filename'); exit 
    end; 
    AssignFile (MyFile, GetCmdLineArg ('editweights', StdSwitchChars)); 
    Reset (MyFile); 
    try 
     while not EOF (MyFile) do 
     begin 
     ReadLn (MyFile, FileLine); 
     WriteLn ('A: ', ExtractWord (1, FileLine, [' ']), 
        '; B: ', ExtractWord (2, FileLine, [' ']), 
        '; W: ', StrToFloat (ExtractWord (3, FileLine, [' '])):0:1); 
     end 
    finally 
     CloseFile (MyFile) 
    end 
end. 

注意我用[' ']而非StdWordDelims,因爲我不想。或者,成爲單詞分隔符。