• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 449
  • Last Modified:

Function to Find word in richedit

Hello guys,

I need a function that must find a word in my richedit, I have a richedit with a sentence, like this:

"she is working with my father and she is eating now"

When I need to find the word "she", my function will find "she" as being the first word, found it, it
must check if the word font color is clyellow, if so, then the function must go on until next word
"she", found the next "she" and not being in word font color clYellow, the function will stop there and
will change the color of "she".

If the word was found and changed its font color, the function will return true.
After finding the word, the function mustn't go on trying to find another word.


This function must have this parents

Function FindWordInText(Word: String; ColorToChange: Tcolor): Boolean

That it, I hope you can understand
Alex
0
hidrau
Asked:
hidrau
1 Solution
 
mikelittlewoodCommented:
This seems to do the trick

uses
   strUtils;

function TForm1.FindWordInText( wordToFind: String; ColorToChange: Tcolor): Boolean;
var
   offset: longInt;
   tempStr: string;
   found, exist: boolean;
begin
   offset := 1;
   found := false;
   exist := false;

   tempStr := uppercase( richEdit1.text);
   while ( not found) and ( offset <> 0) do
   begin
      offset := PosEx( uppercase( wordToFind), tempStr, offset);

      if offset = 0 then
         exist := false
      else begin
         exist := true;

         richEdit1.selStart := offset - 1;
         richEdit1.selLength := length( wordToFind);

         if richEdit1.selAttributes.color = clYellow then
            offset := offset + length( wordToFind)
         else
         begin
            richEdit1.selAttributes.color := clYellow;
            found := true;
         end;
      end;
   end;

   result := exist and found;
end;
0
 
hidrauAuthor Commented:
Hi,

I tested the function and I had a problem on it, I tried to find a word "he" and it got "he" from the word "the", can you fix it?

0
 
hidrauAuthor Commented:
I use RxRichedit and if I have spaces or blank line, the function doesn't work fine :((

0
Get expert help—faster!

Need expert help—fast? Use the Help Bell for personalized assistance getting answers to your important questions.

 
hidrauAuthor Commented:
I noticed that it worked fine in richedit :(((

What must it be? Do you rxLib?
0
 
hidrauAuthor Commented:
Ok, I fixed the problem with rxRichEdit adding this

   tempStr := uppercase(StringReplace(rxrichEdit1.text,#13#10,#10,[rfReplaceAll, rfIgnoreCase]));

But I still have the problem when the word that is added with another, example:

If I try to find "he" it set yellow the he from the word the. Imagine this sentence

She is here with her sister and there is her father

If I ask the function to find the word "er", he will color the "er" from "here" / "sister" / "her" / "father"

I hope you understand
0
 
JohnjcesCommented:
Here's a link or two to nother ways to find text in a memo or RichEdit memo.

http://www.delphipages.com/threads/thread.cfm?ID=109979&G=109966

http://www.delphipages.com/threads/thread.cfm?ID=63344&G=63336

Maybe this will work for you.

John
0
 
hidrauAuthor Commented:
I tried to do but with those examples but the result wasn't good.

:((
0
 
CynnaCommented:
If I understood correctly, this will do it:

function  FindWordInText(Rich : TrichEdit; FindWord:String; TargetColor: Tcolor): Boolean;
// searches *only* whole words in Rich and if FindWord found and its color <> TargetColor, paint it in TargetColor
var i, ws, wl: Integer;
    w, s: String;
    CorrectColor: Boolean;
    function IsDelimiter: Boolean;
    begin
      Result:=TRUE; if i<=1 then Exit;
      Result:=(s[i] in [' ', #10, #13]);
    end;
begin
  Result:=FALSE;
  FindWord:=UpperCase(FindWord); // will be case insensitive
  with Rich do begin
       s:=Trim(Text); SelLength:=1; i:=0;
       repeat
         Inc(i);
         if  IsDelimiter then begin// Word start
            ws:=i+1; wl:=0; CorrectColor:=TRUE;
            if i=1 then begin ws:=1; wl:=1; end; // special case - first word
            repeat // loop though the word - if any char is not in TargetColor, break until another word
               Inc(i); if IsDelimiter then Break;
               Inc(wl);
               SelStart:=i;
               if SelAttributes.Color<>TargetColor then CorrectColor:=FALSE;
            until IsDelimiter or (i>=Length(s));
            Dec(i);
            if not CorrectColor then begin // word in different color found, is it the searched one?
               w:=UpperCase(Copy(s, ws, wl));
               if w=FindWord then begin // correct word, change its color end exit
                  Result:=TRUE; SelStart:=ws-1; SelLength:=wl;
                  SelAttributes.Color:=TargetColor;
                  Exit;
               end;
            end;
         end;
       until i>=Length(s);
  end;
end;
0
 
CynnaCommented:
Oh, and please ignore some of the code comments from your last question, I adapted this function from my last answer to you, so there may be some orphan comments...
0
 
hidrauAuthor Commented:
Hi Cynna,

the function is not working fine if I have my sentence vertically centered. I have a function that center vertically my sentence, I think if this can be fix the function will be ok :))

Please download the example I did
http://www.infosoftlanguages.com.br/arquivos/findword.zip
0
 
hidrauAuthor Commented:
I noticed that there is a comand named find used with richedit, is it not good function to find word in text?

Do you know this? In the link gave by another programmer above it is showed this.

0
 
CynnaCommented:
> the function is not working fine if I have my sentence vertically centered.
> I have a function that center vertically my sentence, I think if this can be fix the function will be ok :))

Yes, this is due to the "s:=Trim(Text);" line (it removes empty lines before actual text). I didn't think of that scenario, sorry - my fault. Now, corrected version below should work fine.


> Please download the example I did

Thank you very much for this. I *love* it when asker posts actual code snippet that couses a problem, it makes the experts job much easier.


> I noticed that there is a comand named find used with richedit, is it not good function to find word in text?

Well, this functions does something similar to what I did. The problem is you want the whole word, while this function searches for any piece of text. So, delimiters (space, enter) marking the end of the word have to be included in search. This may be done using "find" functions, but I see no advantages if this route is taken as opposed to looping through string one char at the time (since inside of any find function you'll find exactly this technique). If there were no "whole word" constriction using find function would make sense.

--------

OK, here comes corrected version:


function TForm1.FindWordInText(Rich : TrichEdit; FindWord:String; TargetColor: Tcolor): Boolean;
// searches *only* whole words in Rich and if FindWord found and its color <> TargetColor, paint it in TargetColor
var i, ws, wl: Integer;
    w, s: String;
    CorrectColor: Boolean;
    function IsDelimiter: Boolean;
    begin
      Result:=TRUE; if i<=1 then Exit;
      Result:=(s[i] in [' ', #10, #13]);
    end;
begin
  Result:=FALSE;
  FindWord:=UpperCase(FindWord); // will be case insensitive
  with Rich do begin
       s:=Text; i:=0;
       repeat
         Inc(i); SelLength:=1;
         if  IsDelimiter then begin// Word start
            ws:=i+1; wl:=0; CorrectColor:=TRUE;
            if i=1 then begin ws:=1; wl:=1; end; // special case - first word
            repeat // loop to the end of the word testing its color
               Inc(i);
               if i>=Length(s) then Break;
               if IsDelimiter then Break;
               Inc(wl);
               SelStart:=i;
               if SelAttributes.Color<>TargetColor then CorrectColor:=FALSE;
            until CorrectColor;
            if i>=Length(s) then Inc(wl);
            Dec(i);
            if not CorrectColor then begin // word in different color found, is it the searched one?
               w:=UpperCase(Copy(s, ws, wl));
               if w=FindWord then begin // correct word, change its color end exit
                  Result:=TRUE; SelStart:=ws-1; SelLength:=wl;
                  SelAttributes.Color:=TargetColor;
                  Exit;
               end;
            end;
         end;
       until i>=Length(s);
  end;
end;

0
 
hidrauAuthor Commented:
Hello Cynna,

Thanks very very much for your help.
Your function is working totaly perfect. I tested it :)))

By the way, where are you from?


0
 
CynnaCommented:
You are very welcome, glad it works OK now.

I'm from Croatia, Europe :)  What made you courious ?
0
 
hidrauAuthor Commented:
Hi Cynna,
the nickname :))

I am from Brazil very far from :))




0
 
hidrauAuthor Commented:
Hi Cynna,

is it possible to improve the function? I noticed that it would be more clever if the word that must be found could be in sequence, for explain this better, see the example:

imagine this sentence

"she is working with her father"

to work in sequence, it could be a parameter that informs the function that it must work in sequence or not, something like this:

FindWordInText(Rich : TrichEdit; FindWord:String; TargetColor: Tcolor; SEQUENCE: boolean): Boolean


it is in yellow until the word "working", so, the next word to be found is "with" but the user is trying to find the word "her",  as the function is working in sequence, it will not color the word "her", only after
"with" it will color the "her".


do you think this could be another thread or it can be done by this?
thanks

0
 
CynnaCommented:
Hi hidrau,
Actually my nick is the way english speakers would pronaunce my "shortened" name. Because my real name is a bit problematic for foreign people to pronounce and remember, I usually missintroduce my self like this... ;))

Now, on to your question...

> it will not color the word "her", only after "with" it will color the "her"
Do you mean that only if "with" is yellow "her" should be coloured? In another words, only if all previous words are coloured in TargetColor the searched word should be coloured?

If I guessed correctly, then the code that implements this:

function FindWordInText2(Rich : TrichEdit; FindWord:String; TargetColor: Tcolor; Sequenced: Boolean): Boolean;
// searches *only* whole words in Rich and if FindWord found and its color <> TargetColor, paint it in TargetColor
// if Sequenced=TRUE then all previous words must be painted in TargetColor also!
var i, ws, wl: Integer;
    w, s: String;
    CorrectColor: Boolean;
    function IsDelimiter: Boolean;
    begin
      Result:=TRUE; if i<=1 then Exit;
      Result:=(s[i] in [' ', #10, #13]);
    end;
begin
  Result:=FALSE;
  FindWord:=UpperCase(FindWord); // will be case insensitive
  with Rich do begin
       s:=Text; i:=0;
       repeat
         Inc(i); SelLength:=1;
         if  IsDelimiter then begin// Word start
            ws:=i+1; wl:=0; CorrectColor:=TRUE;
            if i=1 then begin ws:=1; wl:=1; end; // special case - first word
            repeat // loop to the end of the word testing its color
               Inc(i);
               if i>=Length(s) then Break;
               if IsDelimiter then Break;
               Inc(wl);
               SelStart:=i;
               if SelAttributes.Color<>TargetColor then CorrectColor:=FALSE;
            until (i>=Length(s));
            // if Sequenced and PrevColored then Exit;
            if i>=Length(s) then Inc(wl);
            Dec(i);
            if not CorrectColor then begin // word in different color found, is it the searched one?
               w:=UpperCase(Copy(s, ws, wl));
               if w=FindWord then begin // correct word, change its color end exit
                  Result:=TRUE; SelStart:=ws-1; SelLength:=wl;
                  SelAttributes.Color:=TargetColor;
                  Exit;
               end;
            end;
            // ----- this is the "Sequenced" modification ---------
            // This is not the word we were searching, is it the correct color?
            if not CorrectColor then // Nope, the sequence is "broken"
                   if Sequenced then Exit; // stop any further processing if Sequenced flag is set
         end;
       until i>=Length(s);
  end;
end;


0
 
hidrauAuthor Commented:
wonderful :)))

very very good. Thanks very much.

0
 
hidrauAuthor Commented:
Cynna,

do you get project paid by internet?
0
 
CynnaCommented:
If you mean do I earn any money by working on Internet, then yes I do - and quite a bit, I must confess :)
Although my regular job is at the University, and and has nothing to do with net....

Or did I missunderstood your question?
0
 
hidrauAuthor Commented:
Yeah, you are right.

It is good to know that you can get work by internet.

0
 
CynnaCommented:
> I am having problem on it, when I try to find two our three words

Could you please elaborate? An example representing a problem and an explanation of what is problem would be nice...
0
 
hidrauAuthor Commented:
Hello cynna

I am having problem when I try to find a two word at the same time, imagine this sentence

"I am working with my father and my sister is eating an apple in the kitchen with my mother"

I need to find the "my father" and the function doesn't find it :((

it I find "father" it works fine

did you get it?
0
 
CynnaCommented:
Yes, I understand. The trouble is, your original request was for a single word. Searching for multiple words is a bit more complex...
I'll try to think of something in next minutes, but its 2 in the morning here and I have to be at work in 08.00. So unless some quick wokaround dawns on me, we'll probably talk tomorrow. But don't worry I'll solve it, it's just a question of time.
0
 
CynnaCommented:
OK, try this modification:

function FindWordInText3(Rich : TrichEdit; FindWord:String; TargetColor: Tcolor; Sequenced: Boolean): Boolean;
// searches *only* whole words in Rich and if FindWord found and its color <> TargetColor, paint it in TargetColor
// if Sequenced=TRUE then all previous words must be painted in TargetColor also!
var i, ws, wl: Integer;
    w, s, FindWords: String;
    CorrectColor: Boolean;
    function IsDelimiter: Boolean;
    begin
      Result:=TRUE; if i<=1 then Exit;
      Result:=(s[i] in [' ', #10, #13]);
    end;
begin
  Result:=FALSE;
  FindWord:=UpperCase(FindWord); // will be case insensitive
  with Rich do begin
       s:=UpperCase(Text);
       if Pos(' ', FindWord)>0 then begin // "FindWord" is now actually "FindWords"
          // Quick fix: replace spaces, thus making multiple words be treated with a single word algorithm
          FindWords:=StringReplace(FindWord, ' ', '_', [rfReplaceAll]);
          s:=StringReplace(s, FindWord, FindWords, [rfReplaceAll]);
          FindWord:=FindWords;
       end;
       i:=0;
       repeat
         Inc(i); SelLength:=1;
         if  IsDelimiter then begin// Word start
            ws:=i+1; wl:=0; CorrectColor:=TRUE;
            if i=1 then begin ws:=1; wl:=1; end; // special case - first word
            repeat // loop to the end of the word testing its color
               Inc(i);
               if i>=Length(s) then Break;
               if IsDelimiter then Break;
               Inc(wl);
               SelStart:=i;
               if SelAttributes.Color<>TargetColor then CorrectColor:=FALSE;
            until (i>=Length(s));
            // if Sequenced and PrevColored then Exit;
            if i>=Length(s) then Inc(wl);
            Dec(i);
            if not CorrectColor then begin // word in different color found, is it the searched one?
               w:=Copy(s, ws, wl);
               if w=FindWord then begin // correct word, change its color end exit
                  Result:=TRUE; SelStart:=ws-1; SelLength:=wl;
                  SelAttributes.Color:=TargetColor;
                  Exit;
               end;
            end;
            // ----- this is the "Sequenced" modification ---------
            // This is not the word we were searching, is it the correct color?
            if not CorrectColor then // Nope, the sequence is "broken"
                   if Sequenced then Exit; // stop any further processing if Sequenced flag is set
         end;
       until i>=Length(s);
  end;
end;

0
 
hidrauAuthor Commented:
it must work fine, I am gonna use it for a while to be sure if all is ok,

thanks once again
:))
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Introducing Cloud Class® training courses

Tech changes fast. You can learn faster. That’s why we’re bringing professional training courses to Experts Exchange. With a subscription, you can access all the Cloud Class® courses to expand your education, prep for certifications, and get top-notch instructions.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now