?
Solved

How do I search for text in a stringlist?

Posted on 2010-01-11
17
Medium Priority
?
1,366 Views
Last Modified: 2012-05-08
I'm trying to search for a text in stringlist. I have before used the Pos funktion, but then I have to run throug every line in the StringList and it will take a long time. Then I saw TStringList.Find. Cool, but I have some problems with it. As you can see in the code, I had added some line with ";" as delimiter. I know want to search for "ASO" but it will not work, because the line contain more than just ASO.

I hope the Find is faster than the POS.

Does anyone have an idea on how to solve this?
begin
  strPhoneList := TStringlist.Create;
  strPhoneList.Add('Shevchenko;ASO');
  strPhoneList.Add('Kouzmine;AKE');
  strPhoneList.Add('Jönsson;AJN');
  strPhoneList.Sort;
  if strPhoneList.Find('ASO',index) then
  begin
    strTest := strPhoneList[index];
    for count := 1 to 4 do
      delete(strTest,0,pos(';',strTest));
    strTest := strTest;
  end;
end;

Open in new window

0
Comment
Question by:QC20N
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 6
  • 5
  • 4
  • +1
17 Comments
 
LVL 12

Expert Comment

by:Hypo
ID: 26288503
Actually, looping through each line is not that slow at all... that is what the Find function does with the only difference that it has a smarter search if the list is sorted...

Since you are matching for parts of a line, you dont gain anything by using a sorted line...

If you don't want to loop through each line and use pos on every one, then you can use Pos on the Text property instead of the TStringList instead, but it will probably not be faster than looping through each line and doing a Pos separately, and the position you'll get will not be in Col, Row format... which means you have to recalculate that information if you want it...

just my two cents...
0
 
LVL 4

Expert Comment

by:urban_smurf
ID: 26288710
Hypo is correct, looping through each line is the fastest way to do it and thats what the Find function does.
The following code will loop through each line of the stringlist and check for the string "ASO" using the POS function, if it is found it will then delete the last 4 characters of the string (;ASO) leaving only "Shevchenko" in the strTest string.

Hope that helps!
begin
  strPhoneList := TStringlist.Create;
  strPhoneList.Add('Shevchenko;ASO');
  strPhoneList.Add('Kouzmine;AKE');
  strPhoneList.Add('Jönsson;AJN');
  strPhoneList.Sort;
  For i:= 0 to strPhonelist.count -1 do
  begin
      If pos('ASO',strPhoneList[i]) > 0 then
        begin
          strTest:= strPhoneList[i];
          delete(strTest,len(strTest) -4, 4); 
        End;
   end;
end;

Open in new window

0
 

Author Comment

by:QC20N
ID: 26290892
To: Hypo:
So if you have a phonelist that contain 500 lines and you might need to loop throug phonelist for 8 times more or less. This will not be time consuming?

To: urban_smurf
My phonelist contains lines like this:
Aleksiy;Shevchenko;ASO;498;31220;28101319;Vegetable Oil Tech. Process;357; ;Department Manager;Bent Sarup;Alexey Shevchenko

And what I need in the phonlist is the number after the 4th ";" to the 5th ";"
So the only thing I could come up with was to delete ";" by using the loop in my questioncode from line 10 to 11.

You have another idea?

Btw, what does the len(strTest) do in the delete function?

0
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
LVL 12

Expert Comment

by:Hypo
ID: 26291212
It all depends on what you define as time consuming... in somecases 1 ms can be time consuming, and in other cases it's considered an instant... But anyway... 500 lines is not that much to go through, so I would say that it is not time consuming...

I have written commercial applications myself where I keep references to +100K items in a StringList, and then performs searches which are considered to be performed in an instant. But it all depends on how you write your search algorithm...

I suggest that you read up on algorithm complexity (big oh notation) to get a better understanding of how you can easily determine what algoriothms are godd and what are bad for different scenarios... It's a bit math in this page, but basically what it tries to explain is how to identify how the execution time of an algorithm grows with the size of the data being processed... normally, you never get an algorithm that is better/faster than N, or N * log (N), and you should avoid algorithms that have a complexity of N^2 or N^3   (N^2 means that number of calculations needed in the algorithm grows by the square of the number of data elements it processes)... anyway, here's the link: http://en.wikipedia.org/wiki/Big_O_notation

/Hypo
0
 
LVL 23

Expert Comment

by:Ferruccio Accalai
ID: 26291481
In this case I'd use a simpliest way.

As you have ';' like delimiters in your string you should add your text to the StringList as delimited text.
This will split any text between delimiters ';' into lines.
Then you could simply use IndexOf to find the line.

For Example the following code will return 498



procedure TForm1.Button1Click(Sender: TObject);
function MyFind(PhoneList,SearchString: String):String;
var
strPhoneList :TStrings;
i: Integer;
begin
  result := '';
  strPhoneList := TStringlist.Create;
  try
    strPhoneList.Delimiter := ';';
    StrPhoneList.DelimitedText := PhoneList;
    i := StrPhoneList.indexof(SearchString);
    if (i > -1) and (i < StrPhoneList.Count-1) then
      result := strPhoneList[i+1];
  finally
    strPhoneList.Free;
  end;
end;
begin
ShowMessage(MyFind('Aleksiy;Shevchenko;ASO;498;31220;28101319;Vegetable Oil Tech. Process;357; ;Department Manager;Bent Sarup;Alexey Shevchenko','ASO'));
end;

Open in new window

0
 

Author Comment

by:QC20N
ID: 26291556
If my Phonelist contains this:
Aleksiy;Shevchenko;ASO;498;31220;28101319;Vegetable Oil Tech. Process;357; ;Department Manager;Bent Sarup;Alexey Shevchenko
Alex;Jönsson;AJN;285;21110;21473999;ED Marine&Diesel - Cap.sales;51; ;Regional Marketing Manager;Ole Elrum;Alex Jonsson
Alex;Kouzmine;AKE;313;39130;27778620;Decanter Research;525; ;Automation Engineer;PeterB Blomberg;Alex Kouzmine

and I want to retrieve 31220, 21110 and 39130.

How should I use MyFind function?
0
 
LVL 4

Expert Comment

by:urban_smurf
ID: 26291609
Hi QC20N,
In regards to the speed of parsing stringlists, as Hypo said above, its almost instant (maybe a second or 2) for 100K+ items, so 500 liines will not be an issue.

So just to clarify, from the phone list entry:
Aleksiy;Shevchenko;ASO;498;31220;28101319;Vegetable Oil Tech. Process;357; ;Department Manager;Bent Sarup;Alexey Shevchenko
You are trying to obtain the string 31220 ?

I made a mistake, Len(strTest) should be Length(strTest), and its used to get the length of the string so you know how long it is.

To accomplish the task use the following code, it will always return the string between the 4th and 5th ';' eg '31220'




<input id="gwProxy" type="hidden"><!--Session data--><input onclick="jsCall();" id="jsProxy" type="hidden">
procedure TForm1.Button1Click(Sender: TObject);
var
strPhonelist:Tstringlist;
i,i2:integer; //our counters
strTest,strTemp:String;
begin
  strPhoneList := TStringlist.Create;
  //Add the phonelist line to the stringlist
  strPhonelist.Add('Aleksiy;Shevchenko;ASO;498;31220;28101319;'+
  'Vegetable Oil Tech. Process;357; ;Department Manager;'+
  'Bent Sarup;Alexey Shevchenko');
  //Loop through all list items...
  For i:= 0 to strPhonelist.count -1 do
  begin
  //set our temp string as the listitem
  strTemp:=strPhoneList[i];
    //You only want the string between the 4th and 5th ';'
    for i2:= 1 to 4 do
    Begin
      delete(strTemp,1,pos(';',strTemp));
    End;
  strTest:=copy(strTemp,1,pos(';',strTemp)-1);
  showmessage(strTest);
  End;
End;

Open in new window

0
 
LVL 23

Expert Comment

by:Ferruccio Accalai
ID: 26291622
This phonelist is contained in a file?

These values must be retrieved by searching what? Wich will be the key search to find 31220?
0
 
LVL 4

Expert Comment

by:urban_smurf
ID: 26291635
The code i posted above will retrieve the string between the 4th and 5th ';' for each line loaded into the stringlist.

Hope that helps!
0
 
LVL 23

Expert Comment

by:Ferruccio Accalai
ID: 26291713
I've finally understood what you need.

Here is my example using directly the index (as the needed value is always in the same position).

If the phonelist is stored in a file with carriage returns it's very simply to load it in the list.

My example use a Const value, but there's explained how to do it loading lines from a file
procedure TForm1.Button1Click(Sender: TObject);
var
  List, LineList: TStrings;
  I: Integer;
  s: String;
const
  PhoneList = 'Aleksiy;Shevchenko;ASO;498;31220;28101319;Vegetable Oil Tech. Process;357; ;Department Manager;Bent Sarup;Alexey Shevchenko'+
    #13 +'Alex;Jönsson;AJN;285;21110;21473999;ED Marine&Diesel - Cap.sales;51; ;Regional Marketing Manager;Ole Elrum;Alex Jonsson'+
    #13 +'Alex;Kouzmine;AKE;313;39130;27778620;Decanter Research;525; ;Automation Engineer;PeterB Blomberg;Alex Kouzmine';
begin
  List := TStringList.Create;
  (* If you want to load your phone list from a file use
    List.LoadFromFile('c:\SomePhoneList.txt'); *)
  List.text := PhoneList;
  try
    for I := 0 to List.Count - 1 do
    begin
      LineList := TStringList.Create;
      LineList.Delimiter := ';';
      try
        LineList.DelimitedText := List[I];
        s := s+LineList[4]+' ';
      finally
        LineList.Free;
      end;
    end;
  finally
    List.Free;
  end;
  ShowMessage(s);
end;

Open in new window

0
 

Author Comment

by:QC20N
ID: 26291720
To: Ferruccio68.
Yes, the phonlist is contained in a file and the key search will be the initials: ASO, AKE and AJN in the exampel above.
0
 
LVL 4

Expert Comment

by:urban_smurf
ID: 26291777
dam.... beaten by Ferruccio68 again!
Good example, much better than mine :)
0
 

Author Comment

by:QC20N
ID: 26291790
Your last exampel don't give me a option to put in a searchkey.
0
 
LVL 23

Accepted Solution

by:
Ferruccio Accalai earned 500 total points
ID: 26291798
Now it's really clear, here's your final function
procedure TForm1.Button1Click(Sender: TObject);
  Function MyFind(PhoneListFile, Key: String): String;
  var
    List, LineList: TStrings;
    I, x: Integer;
  begin
    result := '';
    List := TStringList.Create;
    List.LoadFromFile(PhoneListFile);
    try
      for I := 0 to List.Count - 1 do
      begin
        LineList := TStringList.Create;
        LineList.Delimiter := ';';
        try
          LineList.DelimitedText := List[I];
          x := LineList.IndexOf(Key);
          if x > -1 then
          begin
            result := LineList[x+2];
            break;
          end;
        finally
          LineList.Free;
        end;
      end;
    finally
      List.Free;
    end;
  end;

begin
  ShowMessage(MyFind('c:\PhoneList.txt', 'ASO'));
end;

Open in new window

0
 

Author Closing Comment

by:QC20N
ID: 31675803
Perfect.
0
 

Author Comment

by:QC20N
ID: 26293111
To: Ferruccio68

I found a small problem.
if my Phonelist contains this:

Bjarne;Andersen;BANA;360;39120;;Product Centre Decanters;6486; ;Worker;Jan Cederkvist;Bjarne Andersen
John;Albertsen;JAN;775;38710;20973810;E&S;; ;Konsulent;Thomas Fjeldborg;John Albertsen

and my searchkey is: JAN

the result on this is: "Bjarne" and not "38710"

Could you help me with this?
0
 
LVL 23

Expert Comment

by:Ferruccio Accalai
ID: 26293277
That's a Case sensitive issue.
Let's change a little our function to make it work case sensitive
procedure TForm1.Button1Click(Sender: TObject);
  Function MyFind(PhoneListFile, Key: String): String;
  var
    List, LineList: TStringList;
    I, x: Integer;
  begin
    result := '';
    List := TStringList.Create;
    List.LoadFromFile(PhoneListFile);
    try
      for I := 0 to List.Count - 1 do
      begin
        LineList := TStringList.Create;
        LineList.Delimiter := ';';
        LineList.CaseSensitive := True;
        try
          LineList.DelimitedText := List[I];
          x := LineList.IndexOf(Key);
          if x > -1 then
          begin
            result := LineList[x+2];
            break;
          end;
        finally
          LineList.Free;
        end;
      end;
    finally
      List.Free;
    end;
  end;
begin
  ShowMessage(MyFind('c:\PhoneList.txt', 'JAN'));
end;

Open in new window

0

Featured Post

Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

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…
Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
In this video we outline the Physical Segments view of NetCrunch network monitor. By following this brief how-to video, you will be able to learn how NetCrunch visualizes your network, how granular is the information collected, as well as where to f…
Have you created a query with information for a calendar? ... and then, abra-cadabra, the calendar is done?! I am going to show you how to make that happen. Visualize your data!  ... really see it To use the code to create a calendar from a q…
Suggested Courses
Course of the Month8 days, 8 hours left to enroll

764 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