Author: Tomas Rutkauskas
How to Parse the lines of a text file and import them into a Paradox table
I have a text file with a certain format where only the first line is of type year
and month. The rest is always the same: Integer, String, String, Integer, Integer,
Integer. Example:
2001,10
000368,"The Name","Category",000671000,0724690,009421
000701,"The Name","Category",000398500,0398500,005181
What's the best way to import this into Paradox tables?
Answer:
Solve 1:
I would read it one line at a time and parse it with something like the following
parser. The variable ofs needs to be set to zero to start the parsing at the
beginning of the line.
1 { ... }
2 ReadLn(f, line);
3 ofs := 0;
4 if GetNextSepValueOK(line, ofs, YrStr, ', ', '"') and
5 GetNextSepValueOK(line, ofs, MoStr, ', ', '"') then
6 {prep date}
7 else
8 raise Exception.Create('Cannot find year and month');
9 while not EOF(f) do
10 begin
11 ReadLn(f, line);
12 ofs := 0;
13 {Do Append and try, etc. }
14 while GetNextSepValueOK(line, ofs, value, ', ', '"') do
15 {Do Post}
16 end;
17 end;
18 { ... }
19
20 function GetNextSepValueOK(const line: string; var ofs: integer; out value: string;
21 const Separator, Grouper: char): Boolean;
22 var
23 i, oc, lnb, GrouperCount: integer;
24 c: char;
25 temp: ShortString;
26 begin
27 oc := 0;
28 lnb := 0;
29 GrouperCount := 0;
30 i := ofs;
31 while (ofs < length(line)) do
32 begin
33 c := line[ofs + 1];
34 if not Odd(GrouperCount) and (c = Separator) then
35 break
36 else if c = Grouper then
37 begin
38 inc(GrouperCount);
39 if odd(GrouperCount) and (ofs > i) and (line[ofs] = Grouper) then
40 begin
41 inc(oc);
42 temp[oc] := Grouper;
43 end;
44 end
45 else if (c > ' ') or (lnb > 0) or odd(GrouperCount) then
46 begin
47 inc(oc);
48 temp[oc] := c;
49 end;
50 if (c > ' ') or odd(GrouperCount) then
51 lnb := oc;
52 inc(ofs);
53 end;
54 if (ofs < length(line)) and (line[ofs + 1] = Separator) then
55 begin
56 inc(ofs);
57 Result := true;
58 end
59 else
60 Result := (i < length(line)) and not Odd(GrouperCount);
61 if Result then
62 begin
63 temp[0] := char(lnb);
64 value := temp;
65 end;
66 end;
Solve 2:
67 procedure TForm1.ImportFile(const filename: string);
68 var
69 F: Textfile;
70 year, month: Integer;
71 line: string;
72 sl: Tstringlist;
73 begin
74 Assignfile(F, filename);
75 Reset(F);
76 try
77 ReadLn(F, line);
78 sl := TStringlist.Create;
79 try
80 sl.QuoteChar := '"';
81 sl.Commatext := line;
82 year := StrToInt(sl[0]);
83 month := StrToInt(sl[1]);
84 while not EOF(F) do
85 begin
86 Readln(line);
87 sl.Commatext := line;
88 SaveRecord(sl);
89 end;
90 finally
91 sl.free
92 end;
93 finally
94 Closefile(f)
95 end;
96 end;
The Saverecord method would be something like:
97 procedure Tform1.SaveRecord(sl: TStringlist);
98 begin
99 if sl.Count <> 6 then
100 raise Exception.Create('Invalid record');
101 table1.Append;
102 table1['ID'] := sl[0];
103 table2['Name'] := sl[1];
104 { ... }
105 table1.Post;
106 end;
Solve 3:
You can use the CommaText property of a TStringList to parse the lines. Something
like this:
107 procedure ReadFile(FileName: string);
108 var
109 F: TextFile;
110 S: string;
111 List: TStringList;
112 i: integer;
113 begin
114 AssignFile(F, FileName);
115 Reset(F);
116 List := TStringList.Create;
117 try
118 Readln(F, S);
119 List.CommaText := S;
120 {do whatever you want with first line}
121 while not EOF(F) do
122 begin
123 List.Clear;
124 ReadLn(F, S);
125 List.CommaText := S;
126 {List now contains the integers and strings as separate strings}
127 MyTable.Append;
128 for i := 0 to 5 do
129 MyTable.Fields[i].AsString := List.Strings[i];
130 MyTable.Post;
131 end;
132 finally
133 List.Free;
134 end;
135 closefile(f);
136 end;
|