Solved

READING TWO FILES and GENERATING THREE LISTBOXES

Posted on 2003-11-20
13
238 Views
Last Modified: 2010-04-05
Dear experts,


This question is similar my prior question. Now If I have two .txt or .csv files, one a text or list and another a list with three columns.

For example:

text.csv

´Labor leaders said workers at Volkswagen would continue to strike Thursday, while workers at Ford and Mercedes-Benz would most likely slow production by shutting down one area at a time. Ten people representing Ford. Ford favors SMC for unique Explorer cargo box, while GM selects SRIM ´

*********************   *********************
cols.csv

Ford,1924,Car
Volkswagen,1952,Car
Scania,1934,Truck
Busmobil,1927,Bus
Mercedes-Benz,1927,Car
Eliziario,1935,Bus
Jeep,1938,Car
Emack,1919,Truck
GM, 1927,Truck

                            ****************
___________            _____________         ____________
BottonClick1                Botton2Click               Botton3Click
___________             ____________           ___________

-----------------------------------------------------------------------
ListBox1                     ListBox2                      ListBox3

Ford,3                       Car,5                          1924,1
GM,1                         Truck,1                       1927,2
Mercedes-Benz,1                                          1952,1
Volkswagen, 1                                              

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


I looking forward to hearing from you with great interest



j.
0
Comment
Question by:josefkrzysztof
13 Comments
 
LVL 27

Expert Comment

by:kretzschmar
ID: 9794969
? and what is the question ?
0
 
LVL 8

Expert Comment

by:gmayo
ID: 9795842
So in LB1 you want the list of words in the 1st column of the cols.csv which appear in the text.csv file (which is not a CSV file by the way), followed by the number of occurrences?

And in LB2, column 3 this time.

And in LB3, column 2.

?

Geoff.
0
 

Author Comment

by:josefkrzysztof
ID: 9796187
Yes, Gmayo. You underestoodd perfectly my question.

Please ignores full points, commas, interrogation/exclamation points, etc.

The common words between the two files, in truth a text file text.txt instead text.csv and a .csv file. The results must be displayed in three listboxes with its respectives frequencies.


Regards,

J.
0
Announcing the Most Valuable Experts of 2016

MVEs are more concerned with the satisfaction of those they help than with the considerable points they can earn. They are the types of people you feel privileged to call colleagues. Join us in honoring this amazing group of Experts.

 
LVL 2

Expert Comment

by:Robn
ID: 9797537
I wrote this in 10 minutes so please bear with me :)

to use the parser, you would do something like this

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

procedure TForm1.Button1Click(Sender: TObject);
var
  dp: TCarDataParser;
begin
  dp := TCarDataParser.Create('New Text Document.txt');
  try
    dp.ListCarData(dtDivision, Memo1.Lines);
    dp.ListCarData(dtYear, Memo2.Lines);
    dp.ListCarData(dtVehType, Memo3.Lines);
  finally
    dp.Free;
  end;

here is the unit code (I usually place utility code in other units and then link them into my UI units).

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

unit uCarDataParser;

interface

uses
  Classes, Contnrs, SysUtils;

type
  TDataType = (dtDivision, dtYear, dtVehType);

  TCarData = class
  public
    Name: String;
    Occurance: Integer;
    constructor Create;
  end;

  TCarDatas = class(TObjectList)
  private
    function GetItem(Index: Integer): TCarData;
  public
    property Items[Index: Integer]: TCarData read GetItem; default;
    function CreateData(const Name: String): TCarData;
    function IndexOfName(const Name: String): Integer;
  end;

  TCarDataParser = class
  private
    FCarData: array[TDataType] of TCarDatas;
    procedure ParseData(const FileName: String);
  public
    constructor Create(const FileName: String);
    destructor Destroy; override;
    procedure ListCarData(DataType: TDataType; Strings: TStrings);
  end;

implementation

procedure Parse(S: String; cChar: Char; Strings: TStrings);
var
  i,
  OffSet,
  nLength : Integer;
begin
  OffSet := 1;
  nLength := Length(S);
  for i := 1 to nLength do begin
    if S[i] = cChar then begin
      Strings.Add(Copy(S, OffSet, i - OffSet));
      OffSet := Succ(i);
    end;
  end;
  Strings.Add(Copy(S, OffSet, nLength - Pred(OffSet)));
end;

{ TCarDataParser }

constructor TCarDataParser.Create(const FileName: String);
var
  dt: TDataType;
begin
  for dt := Low(dt) to High(dt) do
    FCarData[dt] := TCarDatas.Create;

  if FileExists(FileName) then
    ParseData(FileName);
end;

destructor TCarDataParser.Destroy;
var
  dt: TDataType;
begin
  for dt := Low(dt) to High(dt) do
    FCarData[dt].Free;

  inherited;
end;

procedure TCarDataParser.ListCarData(DataType: TDataType;
  Strings: TStrings);
var
  i: Integer;
  Data: TCarDatas;
begin
  Data := FCarData[DataType];
  for i := 0 to Data.Count - 1 do begin
    Strings.Add(Data[i].Name+','+IntToStr(Data[i].Occurance));
  end;
end;

procedure TCarDataParser.ParseData(const FileName: String);
var
  i: Integer;
  Data, Items: TStringList;
  ///////
  procedure ProcessName(Index: Integer; dt: TDataType);
  begin
    if Index < Items.Count then begin
      FCarData[dt].CreateData(Trim(Items[Index]));
    end;
  end;
begin
  Data := TStringList.Create;
  Items := TStringList.Create;
  try
    Data.LoadFromFile(FileName);
    for i := 0 to Data.Count - 1 do begin
      Items.Clear;
      Parse(Data[i], ',', Items);
      ProcessName(0, dtDivision);
      ProcessName(1, dtYear);
      ProcessName(2, dtVehType);
    end;
  finally
    Data.Free;
    Items.Free;
  end;
end;

{ TCarDatas }

function TCarDatas.CreateData(const Name: String): TCarData;
var
  Index: Integer;
begin
  Index := IndexOfName(Name);
  if Index > -1 then begin
    Inc(Items[Index].Occurance);
    result := Items[Index];
  end else begin
    result := TCarData.Create;
    Add(result);
    result.Name := Name;
  end;
end;

function TCarDatas.GetItem(Index: Integer): TCarData;
begin
  result := TCarData(Get(Index));
end;

function TCarDatas.IndexOfName(const Name: String): Integer;
var
  i: Integer;
begin
  for i := 0 to Count - 1 do begin
    if Items[i].Name <> Name then Continue;
    result := i;
    Exit;
  end;
  result := -1;
end;

{ TCarData }

constructor TCarData.Create;
begin
  Occurance := 1;
end;

end.


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

You can optimize the code quite a but by doing a binary search on the IndexOfName function.
If you have any questions, I would be more then happy to help you out.

Hope this helps,
Rob
0
 
LVL 2

Accepted Solution

by:
Robn earned 140 total points
ID: 9797710
Sorry, I wasn't happy with what I had origionally posted. I don't like having the constructor of a class do any work in the event an exception is raised. Here is the new code.

to use the parser, you would do something like this

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

procedure TForm1.Button1Click(Sender: TObject);
var
  dp: TCarDataParser;
begin
  dp := TCarDataParser.Create;
  try
    dp.ParseData('New Text Document.txt');
    dp.ListCarData(dtDivision, Memo1.Lines);
    dp.ListCarData(dtYear, Memo2.Lines);
    dp.ListCarData(dtVehType, Memo3.Lines);
  finally
    dp.Free;
  end;  
end;

here is the unit code (I usually place utility code in other units and then link them into my UI units).

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

unit uCarDataParser;

interface

uses
  Classes, Contnrs, SysUtils;

type
  TDataType = (dtDivision, dtYear, dtVehType);

const
  IndexValue: array[TDataType] of Integer = (0, 1, 2);

type
  TCarData = class
  public
    Name: String;
    Occurance: Integer;
    constructor Create;
  end;

  TCarDatas = class(TObjectList)
  private
    function GetItem(Index: Integer): TCarData;
  public
    property Items[Index: Integer]: TCarData read GetItem; default;
    function CreateData(const Name: String): TCarData;
    function IndexOfName(const Name: String): Integer;
  end;

  TCarDataParser = class
  private
    FCarData: array[TDataType] of TCarDatas;
    procedure ClearData;
  public
    constructor Create;
    destructor Destroy; override;
    procedure ParseData(const FileName: String);
    procedure ListCarData(DataType: TDataType; Strings: TStrings);
  end;

implementation

procedure Parse(S: String; cChar: Char; Strings: TStrings);
var
  i,
  OffSet,
  nLength : Integer;
begin
  OffSet := 1;
  nLength := Length(S);
  for i := 1 to nLength do begin
    if S[i] = cChar then begin
      Strings.Add(Copy(S, OffSet, i - OffSet));
      OffSet := Succ(i);
    end;
  end;
  Strings.Add(Copy(S, OffSet, nLength - Pred(OffSet)));
end;

{ TCarDataParser }

procedure TCarDataParser.ClearData;
var
  dt: TDataType;
begin
  for dt := Low(dt) to High(dt) do
    FCarData[dt].Clear;
end;

constructor TCarDataParser.Create;
var
  dt: TDataType;
begin
  for dt := Low(dt) to High(dt) do
    FCarData[dt] := TCarDatas.Create;
end;

destructor TCarDataParser.Destroy;
var
  dt: TDataType;
begin
  for dt := Low(dt) to High(dt) do
    FCarData[dt].Free;

  inherited;
end;

procedure TCarDataParser.ListCarData(DataType: TDataType;
  Strings: TStrings);
var
  i: Integer;
  Data: TCarDatas;
begin
  Data := FCarData[DataType];
  for i := 0 to Data.Count - 1 do begin
    Strings.Add(Data[i].Name+','+IntToStr(Data[i].Occurance));
  end;
end;

procedure TCarDataParser.ParseData(const FileName: String);
var
  i: Integer;
  dt: TDataType;
  Data, Items: TStringList;
  ///////
  procedure ProcessName(dt: TDataType);
  var
    Index: Integer;
  begin
    Index := IndexValue[dt];
    if Index < Items.Count then begin
      FCarData[dt].CreateData(Trim(Items[Index]));
    end;
  end;
begin
  ClearData;
  if not FileExists(FileName) then Exit;

  Data := TStringList.Create;
  Items := TStringList.Create;
  try
    Data.LoadFromFile(FileName);
    for i := 0 to Data.Count - 1 do begin
      Items.Clear;
      Parse(Data[i], ',', Items);
      for dt := Low(dt) to High(dt) do begin
        ProcessName(dt);
      end;
    end;
  finally
    Data.Free;
    Items.Free;
  end;
end;

{ TCarDatas }

function TCarDatas.CreateData(const Name: String): TCarData;
var
  Index: Integer;
begin
  Index := IndexOfName(Name);
  if Index > -1 then begin
    Inc(Items[Index].Occurance);
    result := Items[Index];
  end else begin
    result := TCarData.Create;
    Add(result);
    result.Name := Name;
  end;
end;

function TCarDatas.GetItem(Index: Integer): TCarData;
begin
  result := TCarData(Get(Index));
end;

function TCarDatas.IndexOfName(const Name: String): Integer;
var
  i: Integer;
begin
  for i := 0 to Count - 1 do begin
    if Items[i].Name <> Name then Continue;
    result := i;
    Exit;
  end;
  result := -1;
end;

{ TCarData }

constructor TCarData.Create;
begin
  Occurance := 1;
end;

end.
0
 

Author Comment

by:josefkrzysztof
ID: 9799454
Dear Robn,

Thank you for your script and helpful.

Please, I am a beginner in Delphi. You are working with two UNITS, right? and only a FORM?

so long.

j.
0
 

Author Comment

by:josefkrzysztof
ID: 9799464
Other thing...

Do you are working in Delphi 5?

j.
0
 
LVL 2

Expert Comment

by:Robn
ID: 9799512
I'm working with D7, but the code will work in D5.
Create a new unit called uCarDataParser. Paste the code starting at

unit uCarDataParser
down to
end.

into your new unit. Add uCarDataParser to the uses of your Form unit and that is it.
If you want, you can place 3 memo's on the form and a button. My sample code should work then.

Another thing I noticed in some posts I have read is that they don't like "homework" on this site. I didn't realise this at the time I posted it so take the code and use it wisely while it is still here :)

Enjoy,
Rob
0
 

Author Comment

by:josefkrzysztof
ID: 9799619
Ok. Was created a unit called uCarDataParser. The memos (1,2,3) are in Form1. This is the project file:

begin
  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.

It Run however it does nothing.



j.
0
 
LVL 2

Expert Comment

by:Robn
ID: 9799751
can I e-mail you the code?
0
 

Author Comment

by:josefkrzysztof
ID: 9799782
Yes.
dicionarios@ig.com.br

Thank you

j.
0
 

Author Comment

by:josefkrzysztof
ID: 9800746
Robn,

Your script works very, very fine. however, there is a problem.

Your threee memos are right and iis idealization, however you
must bear in mind there is necessary to have a .txt file whose words
must be compared with a 2nd file with the following structure:

Ford,1924,Car
Volkswagen,1952,Car
Scania,1934,Truck

The results of the combination must generates the form1 you generated.

Many thanks again.

j.
0
 

Author Comment

by:josefkrzysztof
ID: 9819400
Many thanks!

j.
0

Featured Post

Announcing the Most Valuable Experts of 2016

MVEs are more concerned with the satisfaction of those they help than with the considerable points they can earn. They are the types of people you feel privileged to call colleagues. Join us in honoring this amazing group of Experts.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
Along with being a a promotional video for my three-day Annielytics Dashboard Seminor, this Micro Tutorial is an intro to Google Analytics API data.
This video shows how to quickly and easily add an email signature for all users on Exchange 2016. The resulting signature is applied on a server level by Exchange Online. The email signature template has been downloaded from: www.mail-signatures…

805 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question