It seems interesting. 

I'vre archived it, and will have a look when there is available time or mood...

Thx and Well done..


--- Óôéò Ôñßô., 19/05/09, ï/ç Theodoros Bebekis <[email protected]> Ýãñáøå:

Áðü: Theodoros Bebekis <[email protected]>
ÈÝìá: Re: [delphi-en] CVS Parser?
Ðñïò: [email protected], [email protected], 
[email protected]
Çìåñïìçíßá: Ôñßôç, 19 ÌÜéïò 2009, 15:07




> 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






      
___________________________________________________________ 
×ñçóéìïðïéåßôå Yahoo!; 
ÂáñåèÞêáôå ôá åíï÷ëçôéêÜ ìçíýìáôá (spam); Ôï Yahoo! Mail 
äéáèÝôåé ôçí êáëýôåñç äõíáôÞ ðñïóôáóßá êáôÜ ôùí åíï÷ëçôéêþí 
ìçíõìÜôùí http://login.yahoo.com/config/mail?.intl=gr 


[Non-text portions of this message have been removed]



------------------------------------

-----------------------------------------------------
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/

Reply via email to