> From: [email protected] <mailto:delphi-en%40yahoogroups.com>
> [mailto:[email protected] <mailto:delphi-en%40yahoogroups.com>]
> On Behalf
> Of Theodoros Bebekis
> Sent: Monday, May 18, 2009 10:41 AM
> To: [email protected] <mailto:delphi-en%40yahoogroups.com>
> Subject: [delphi-en] CVS Parser?
>
> Hi
>
> Is there any freeware CVS parser out there for Delphi 6-7?
> One that can handle fields containing line breaks (CRLF), double quotes, and
> commas
> according to the CVS spec (http://tools.ietf.org/html/rfc4180
> <http://tools.ietf.org/html/rfc4180>)?
>
> --
> Regards
> Theo
I finally wrote a csv parser. I took the parsing code
from TStrings.SetDelimitedText() private method.
In case anyone has a need of such a code, here is the unit.
Use it at your own risk.
//=============================================================
unit o_CSVParser;
interface
uses
Windows
,SysUtils
,Classes
,Controls
,Contnrs
,Types
,DB
;
type
(*----------------------------------------------------------------------------
Represents a line in the source file. Used internally by the parser
----------------------------------------------------------------------------*)
TLine = class(TObject)
private
Fields : TStringDynArray;
public
constructor Create(FieldCount: Integer);
end;
(*----------------------------------------------------------------------------
Parses .csv files
Provides two Parse() methods.
1. The first Parse() version parses data and creates an internal list of
TLine objects.
After successful parsing (LineCount > 0) access parsed data using the
function GetValue(const LineIndex, FieldIndex: Integer): string;
2. The second Parse() version parses data into an already created and Active
TDataset.
Example:
Table := TClientDataSet.Create(Self);
Table.FieldDefs.Add('CODE' , ftString, 32);
Table.FieldDefs.Add('DATE' , ftString, 24);
Table.FieldDefs.Add('AMOUNT' , ftString, 16);
Table.FieldDefs.Add('DEBIT_CREDIT' , ftString, 8);
Table.FieldDefs.Add('CURRENCY_CODE' , ftString, 8);
Table.FieldDefs.Add('VAT_CODE' , ftString, 8);
Table.CreateDataSet();
Table.Active := True;
ParseCSV('FileName.csv', Table, True, ';');
----------------------------------------------------------------------------*)
TCSVParser = class(TObject)
private
FList : TObjectList;
FFieldCount : Integer;
FDelimiter : AnsiChar;
FMS : TMemoryStream;
FFieldIndex : Integer;
FInFirstLine : Boolean;
FSkipFirstLine : Boolean;
FCurrentLine : TLine;
FToDataset : Boolean;
FTable : TDataset;
procedure ExtractValues(P: PChar);
procedure AddFieldValue(const S: string);
function get_LineCount: Integer;
procedure DoParse(const FileName: string; FieldCount: Integer;
SkipFirstLine: Boolean; Delimiter: AnsiChar);
public
constructor Create;
destructor Destroy; override;
procedure Clear;
procedure Parse(const FileName: string; FieldCount: Integer;
SkipFirstLine: Boolean; Delimiter: AnsiChar = ';' ); overload;
procedure Parse(const FileName: string; Table: TDataset; SkipFirstLine:
Boolean; Delimiter: AnsiChar = ';'); overload;
function GetValue(const LineIndex, FieldIndex: Integer): string;
property LineCount : Integer read get_LineCount;
end;
procedure ParseCSV(const FileName: string; Table: TDataset; SkipFirstLine:
Boolean; Delimiter: AnsiChar = ';');
implementation
(*----------------------------------------------------------------------------
Parses FileName source file into Table TDataset.
The Table must be already created and Active.
Set SkipFirstLine to True when the first line in the source file contains
field names
Delimiter is the field delimiter character
----------------------------------------------------------------------------*)
procedure ParseCSV(const FileName: string; Table: TDataset; SkipFirstLine:
Boolean; Delimiter: AnsiChar);
var
Parser: TCSVParser;
begin
Parser := TCSVParser.Create;
try
Parser.Parse(FileName, Table, SkipFirstLine, Delimiter);
finally
Parser.Free;
end;
end;
{ TLine }
(*----------------------------------------------------------------------------*)
constructor TLine.Create(FieldCount: Integer);
begin
inherited Create;
SetLength(Fields, FieldCount);
end;
{ TCSVParser }
(*----------------------------------------------------------------------------*)
constructor TCSVParser.Create;
begin
inherited Create;
FList := TObjectList.Create(True);
end;
(*----------------------------------------------------------------------------*)
destructor TCSVParser.Destroy;
begin
FList.Free;
inherited;
end;
(*----------------------------------------------------------------------------*)
procedure TCSVParser.Clear;
begin
FList.Clear;
FFieldCount := 0;
FDelimiter := ';';
FFieldIndex := 0;
FInFirstLine := True;
end;
(*----------------------------------------------------------------------------*)
function TCSVParser.get_LineCount: Integer;
begin
Result := FList.Count
end;
(*----------------------------------------------------------------------------*)
function TCSVParser.GetValue(const LineIndex, FieldIndex: Integer): string;
begin
Result := TLine(FList[LineIndex]).Fields[FieldIndex];
end;
(*----------------------------------------------------------------------------*)
procedure TCSVParser.AddFieldValue(const S: string);
begin
if FSkipFirstLine and FInFirstLine then
begin
Inc(FFieldIndex);
if FFieldIndex > FFieldCount - 1 then
begin
FInFirstLine := False;
FFieldIndex := 0;
end;
end else if FToDataset then
begin
if FFieldIndex = 0 then
begin
FTable.Append;
FTable.Edit();
end;
FTable.Fields[FFieldIndex].Value := S;
Inc(FFieldIndex);
if FFieldIndex > FFieldCount - 1 then
begin
FTable.Post();
FFieldIndex := 0;
end;
end else begin
if FFieldIndex = 0 then
FCurrentLine := TLine.Create(FFieldCount);
FCurrentLine.Fields[FFieldIndex] := S;
Inc(FFieldIndex);
if FFieldIndex > FFieldCount - 1 then
begin
FList.Add(FCurrentLine);
FFieldIndex := 0;
end;
end;
end;
(*----------------------------------------------------------------------------
parsing code is stolen from TStrings.SetDelimitedText() private method
----------------------------------------------------------------------------*)
procedure TCSVParser.ExtractValues(P: PChar);
var
P1: PChar;
S: string;
begin
while P^ in [#1..' '] do
P := CharNext(P);
while P^ <> #0 do
begin
if P^ = '"' then
S := AnsiExtractQuotedStr(P, '"')
else begin
P1 := P;
while (P^ > ' ') and (P^ <> FDelimiter) do
P := CharNext(P);
SetString(S, P1, P - P1);
end;
AddFieldValue(S); // <====
while P^ in [#1..' '] do
Inc(P);
if P^ = FDelimiter then
begin
P1 := P;
if CharNext(P1)^ = #0 then
AddFieldValue(''); // <====
repeat
P := CharNext(P);
until not (P^ in [#1..' ']);
end;
end;
end;
(*----------------------------------------------------------------------------*)
procedure TCSVParser.DoParse(const FileName: string; FieldCount: Integer;
SkipFirstLine: Boolean; Delimiter: AnsiChar);
var
NUL : Char;
begin
FFieldCount := FieldCount;
FDelimiter := Delimiter;
FSkipFirstLine := SkipFirstLine;
if FileExists(FileName) then
begin
FMS := TMemoryStream.Create;
try
FMS.LoadFromFile(FileName);
FMS.Position := 0;
if FMS.Size > 0 then
begin
FMS.Position := FMS.Position + FMS.Size;
NUL := #0;
FMS.WriteBuffer(NUL, 1);
FMS.Position := 0;
ExtractValues(FMS.Memory);
end;
finally
FMS.Free;
end;
end;
end;
(*----------------------------------------------------------------------------
Parses FileName source file.
FieldCount is the number of fields in the FileName source file
Set SkipFirstLine to True when the first line in the source file contains
field names
Delimiter is the field delimiter character
After successful parsing (LineCount > 0) access parsed data using the
function GetValue(const LineIndex, FieldIndex: Integer): string;
----------------------------------------------------------------------------*)
procedure TCSVParser.Parse(const FileName: string; FieldCount: Integer;
SkipFirstLine: Boolean; Delimiter: AnsiChar);
begin
Clear();
FToDataset := False;
DoParse(FileName, FieldCount, SkipFirstLine, Delimiter);
end;
(*----------------------------------------------------------------------------
Parses FileName source file into Table TDataset.
The Table must be already created and Active.
Set SkipFirstLine to True when the first line in the source file contains
field names
Delimiter is the field delimiter character
----------------------------------------------------------------------------*)
procedure TCSVParser.Parse(const FileName: string; Table: TDataset;
SkipFirstLine: Boolean; Delimiter: AnsiChar);
begin
Clear();
FToDataset := True;
FTable := Table;
DoParse(FileName, Table.FieldCount, SkipFirstLine, Delimiter);
end;
end.
--
Regards
Theo
------------------------
Theo Bebekis
Thessaloniki, Greece
------------------------
C# and Delphi tutorials at http://teo.bebekis.googlepages.com/
------------------------
Greek_Delphi_Prog : a greek Delphi list at
http://groups.yahoo.com/group/Greek_Delphi_Prog
CSharpDotNetGreek : a greek C# and .Net list at
http://groups.yahoo.com/group/CSharpDotNetGreek
atla_custom : an ALTEC Atlantis Customization list at
http://groups.yahoo.com/group/atla_custom
------------------------
------------------------------------
-----------------------------------------------------
Home page: http://groups.yahoo.com/group/delphi-en/
To unsubscribe: [email protected]! Groups Links
<*> To visit your group on the web, go to:
http://groups.yahoo.com/group/delphi-en/
<*> Your email settings:
Individual Email | Traditional
<*> To change settings online go to:
http://groups.yahoo.com/group/delphi-en/join
(Yahoo! ID required)
<*> To change settings via email:
mailto:[email protected]
mailto:[email protected]
<*> To unsubscribe from this group, send an email to:
[email protected]
<*> Your use of Yahoo! Groups is subject to:
http://docs.yahoo.com/info/terms/