Solved

Searching for a word using wildcards

Posted on 1998-06-10
11
326 Views
Last Modified: 2010-04-04
I want to find the position of a word in a TRichEdit using the characters $ (meaning a vocal), £ (meaning a consonant), # (meaning a double consonant)  and * (meaning any number greater than zero of arbitrary letters). The search word may contain any number and combinations of these four wildcards. Thus, searching for ' *$s*'  would find the word 'close' (but not 'estimate')  and  '*$# '  would find 'fill' (but not 'fil' or 'filling').

I would like a complete algorithm or preferably a working Delphi function.
0
Comment
Question by:toreot
  • 4
  • 3
  • 2
  • +2
11 Comments
 
LVL 1

Expert Comment

by:Marcius
ID: 1351969
What do you mean by "a vocal" ? I do not understand the term
0
 
LVL 8

Expert Comment

by:ZifNab
ID: 1351970
have a look at this library :

http://www.mindspring.com/~efd/hyperstr.htm

regards, ZiF.
0
 
LVL 1

Expert Comment

by:Marcius
ID: 1351971
That looks very nice, see above, sounds like it may provide the solution.
0
 
LVL 1

Expert Comment

by:Greedy
ID: 1351972
I saw an artical in Delphi informant that did this (kinda)...It was called Soundex algorithms...they used it for a name look up so that if you had data entry order takers get someones name from them they could put it in an edit box an it would find the name even if it wasn't spelled right.  (ie Stevens and Stephens)
go to
http://www.informant.com/delphi/DI3XL.HTM  
the file name is: DI9803RS.ZIP

0
 

Author Comment

by:toreot
ID: 1351973
I will take a look as soon as possible. By the way, I should have checked my English. 'Vokal' in Norwegian is 'vowel' in English.
0
Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

 
LVL 1

Expert Comment

by:Marcius
ID: 1351974
Check your example also, estimate and close both have a vowel followed by 's' ;)
0
 

Author Comment

by:toreot
ID: 1351975
Yes, but the * in front means that there should be one or more letters in front of the vowel before the s, and 'estimate' starts with the vowel. I should also make it clear that # means two IDENTICAL consonants (bb etc.).
I have looked into the hyperstring library and although it contains many useful functions, I am fairly sure they are too general to solve my problem.

If the original problem seems too daunting, the following simplication would also be useful:
At most one each of #, £, $ and at most two *, one in front and one in the back of the word. At most one substring of letters.

Now I could probably write it myself given enough time, but is there a more experienced programmer out there who takes the challenge? I may increase the points to 500.
0
 
LVL 1

Expert Comment

by:Socrates050697
ID: 1351976
I've got something similar that I'm just converting to your needs. I should have it done soon. A couple of questions :-

Do you need it to be case sensitive or not?

Are you only searching for whole words i.e.

for the sentence - 'my walls are red' and a search of  - wa#*
i assume you want the answer 'walls' not 'walls are red'

Socrates
0
 

Author Comment

by:toreot
ID: 1351977
It should not be case sensitive and  I only want to find whole words.
0
 
LVL 1

Accepted Solution

by:
Socrates050697 earned 500 total points
ID: 1351978
I was intending to get this to you yesterday but something croped up at work. Anyway here it is.

The way to use it to call 'WildSearch' sending it the Search String ( e.g. *#s),your TRichEdit control, and a TList wich you have already created. The functions return value is the number of matches found and the TList is returned with pointers to TWordRec records (defined at the top of the unit). This contains the line number, the position on that line and the length of the word that mathes your search string.
Note that the TList is initially cleared by WIldSearch.

Its a little rough and ready, but it does the job. I'm not sure how fast it is. I've tried it with a couple of hundred lines of text and it seems ok.

If you've got any other questions about this bit of code, feel free to contact me and I'll be happy to make any alterations or whatever. I'll be away all weekend so it'll either have to be today or next week. I've included the whole unit below, which includes a form with a TRichEdit, a TEdit (Called SearchEdit) and a Button which make a simple demonstration of it.

Hope this helps you out.




unit search;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ComCtrls;

const
  Vowels=['A','E','I','O','U','a','e','i','o','u'];
  Consanants=['b','c','d','f','g','h','j','k','l','m','n','p','q','r',
              's','t','v','w','x','y','z','B','C','D','F','G','H','J','K','L',
              'M','N','P','Q','R','S','T','V','W','X','Y','Z'];
  WildCards=['£','$','#','*'];

type
  TWordRec = record
    Line: integer;
    Position: integer;
    Length: integer;
  end;
  PTWordRec=^TWordrec;

  TForm1 = class(TForm)
    RichEdit1: TRichEdit;
    Button1: TButton;
    SearchEdit: TEdit;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

function isVowel(MyChar: Char): Boolean;
function isConsanant(MyChar: Char): Boolean;
function isLetter(MyChar: Char): Boolean;
function isLetterorWildCard(MyChar: Char): Boolean;
function TextSearch(text,SearchStr: string;AtStart: Boolean;var position,Reslength: integer): Boolean;
function WildSearch(SearchStr: String;MyEdit: TRichEdit;var AList: TList): integer;


implementation

{$R *.DFM}




function TextSearch(text,SearchStr: string;AtStart: Boolean;var position,Reslength: integer): Boolean;
var
  Count, SubCount, Tester: integer;
  Continue, KeepGoing: Boolean;
  TempPos,TempLength: integer;
begin
  Count:=1;
  KeepGoing:=True;
  while KeepGoing and (Count<=Length(Text)) do
  begin
    if AtStart then KeepGoing:=False;
    SubCount:=0;
    Continue:=True;
    Tester:=1;
    while Continue and (Tester<=Length(SearchStr)) do
    begin
      Continue:=False;
      Case SearchStr[Tester] of
        // Vowel
        '$' : begin
          if isVowel(Text[Count+SubCount]) then
          begin
            Continue:=True;
            inc(Tester);
            inc(SubCount);
          end;
        end;
        // Consanant
        '£' : begin
          if isConsanant(Text[Count+SubCount]) then
          begin
            Continue:=True;
            inc(Tester);
            inc(SubCount);
          end;
        end;
        // Double consanant
        '#' : begin
          if isConsanant(Text[Count+SubCount]) and (AnsiLowerCase(Text[Count+SubCount])=AnsiLowerCase(Text[Count+SubCount+1])) then
          begin
            Continue:=True;
            inc(Tester,1);
            inc(SubCount,2);
          end;
        end;
        // Some Letters
        '*' : begin
            inc(Tester);
          if Tester>Length(SearchStr) then
          begin
            Continue:=True;
            Tester:=Length(SearchStr)+1;
            if SubCount=(Length(Text)-Count+1) then
              Continue:=False
            else
              SubCount:=Length(Text)-Count+1;
          end
          else if TextSearch(Copy(Text,Count+SubCount+1,Length(Text)-(Count+SubCount)),Copy(SearchStr,Tester,Length(SearchStr)-Tester+1),False,TempPos,TempLength) then
          begin
            Continue:=True;
            Tester:=Length(SearchStr)+1;
            SubCount:=SubCount+TempLength+TempPos;
          end;
        end;
        else begin
          if AnsiLowerCase(Text[Count+SubCount])=AnsiLowerCase(SearchStr[Tester]) then
          begin
            Continue:=True;
            inc(Tester);
            inc(SubCount);
          end;
        end;
      end;
    end;
    if AtStart and ((SubCount)<Length(Text)) then Continue:=False;
    if Continue then
    begin
      Position:=Count;
      ResLength:=SubCount;
      Result:=True;
      exit;
    end;
    inc(Count);
  end;
  Result:=False;
  Position:=0;
  ResLength:=0;
end;

function isVowel(MyChar: Char): Boolean;
begin
  If MyChar in Vowels then
    result:=True
  else
    result:=False;
end;

function isConsanant(MyChar: Char): Boolean;
begin
  If MyChar in Consanants then
    result:=True
  else
    result:=False;
end;

function isLetter(MyChar: Char): Boolean;
begin
  if isVowel(MyChar) or isConsanant(MyChar) then
    result:=True
  else
    result:=False;
end;

function isLetterOrWildCard(MyChar: Char): Boolean;
begin
  if isLetter(MyChar) or (MyChar in WildCards) then
    result:=True
  else
    result:=False;
end;

function WildSearch(SearchStr: String;MyEdit: TRichEdit;var AList: TList): integer;
var
  TestStr: string;
  WordStart,WordEnd: integer;
  TestWord: string;
  n,m: integer;
  Position,ResLength: integer;
  WordRec: PTWordRec;
begin
  AList.Clear;
  For n:=0 to MyEdit.Lines.Count-1 do
  begin
    TestStr:=MyEdit.Lines[n];
    if TestStr<>'' then
    begin
      TestWord:='';
      WordStart:=1;
      While not isLetter(TestStr[WordStart]) do
        inc(WordStart);
      For m:=WordStart to Length(TestStr) do
      begin
        if isLetter(TestStr[m]) then
        begin
          TestWord:=TestWord+TestStr[m];
          WordEnd:=m;
          if (m=Length(TestStr)) or (not isLetter(TestStr[m+1])) then
          begin
            if TextSearch(TestWord,SearchStr,True,Position,ResLength) then
            begin
              New(WordRec);
              WordRec.Line:=n;
              WordRec.Position:=WordStart;
              WordRec.Length:=WordEnd-WordStart+1;
              AList.Add(WordRec);
            end;
            WordStart:=WordEnd;
            TestWord:='';
          end;
        end
        else
          WordStart:=m+1;
      end;
    end;
  end;
  Result:=AList.Count;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  MyList: TList;
  Number,n: integer;
  WordRec: PTWordRec;
begin
  MyList:=TList.Create;
  try
    Number:=WildSearch(SearchEdit.Text,RichEdit1,MyList);
    for n:=0 to Number-1 do
    begin
      WordRec:=MyList[n];
      ShowMessage(Copy(RichEdit1.Lines[WordRec.Line],WordRec.Position,WordRec.Length));
    end;
  finally
    MyList.Free;
  end;
end;

0
 

Author Comment

by:toreot
ID: 1351979
It seems to work beautifully. Just what I needed. I will give you 500 points.
0

Featured Post

6 Surprising Benefits of Threat Intelligence

All sorts of threat intelligence is available on the web. Intelligence you can learn from, and use to anticipate and prepare for future attacks.

Join & Write a Comment

Have you ever had your Delphi form/application just hanging while waiting for data to load? This is the article to read if you want to learn some things about adding threads for data loading in the background. First, I'll setup a general applica…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
Here's a very brief overview of the methods PRTG Network Monitor (https://www.paessler.com/prtg) offers for monitoring bandwidth, to help you decide which methods you´d like to investigate in more detail.  The methods are covered in more detail in o…
This video gives you a great overview about bandwidth monitoring with SNMP and WMI with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're looking for how to monitor bandwidth using netflow or packet s…

758 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

Need Help in Real-Time?

Connect with top rated Experts

21 Experts available now in Live!

Get 1:1 Help Now