2012-03-22 34 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,因为我不想。或者,成为单词分隔符。