Page 1 of 1

is there something like a Split function?

Posted: Thu Dec 22, 2005 9:29 am
by toolwiz
I have some macro tags that I need to expand, and I'm concerned about the SearchText function getting hung in a loop searching for them. (It's happened once now.)

Is there a way to easily parse the entire text in an RVE into words and non-words -- like a kind of Split function that would break words and non-words into individual Items? It can use a set of delimiters to distinguish words. This would allow me to iterate over the list of items myself.

Any group of characters that is distinguished as a "word" can have its style set to, eg., 0, and the other chunks of non-word text can have their style set to some other value. Or its Tag value. Just something I can check to quickly know if an item is a legitimate word or not.

Alternately, I can use a way to simply step through a document, word-by-word, where words are defined by a set of delimiters. (There's a function to SelectCurrWord that uses a delimter set, but it seems to be designed to be called in response to a mouse click.)

Thanks.
-David

Posted: Thu Dec 22, 2005 1:17 pm
by shmp
Helpful clues. GetItemStyle tells if the item is above '0' or negative. Anything negative is none text, even labeled items.

Cheers.

Posted: Fri Dec 23, 2005 7:40 am
by toolwiz
shmp wrote:Helpful clues. GetItemStyle tells if the item is above '0' or negative. Anything negative is none text, even labeled items.

Cheers.
Initially there is one item that exists for the entire document. I'm trying to find out what is the best way to split up all of the words in the document so they are individual items. Then, yes, GetItemStyle will tell me this.

The functions I've found seem to be designed around the assumption that the user is selecting some text, and the program is responding to that selection. The only function I've found where the program automatically selects words is the spelling checker function. But it does not say whether it splits the words it finds into Items.

Isn't there some simple way to have an RVEdit parse itself into words? The only other solution is iterating character-by-character through the buffer and calling SetSelectionBounds for each word that's found. But ... it's not clear from the Help text that even THIS function establishes a distinct Item. In fact, one thing I find that's a big "missing" throughout the help text is that few if any of the functions say whether they create an Item or not.

I'd really love to get some more insight into this.

Thanks
-David

Posted: Fri Dec 23, 2005 12:11 pm
by Guest
In actual fact there is a simpler way, using rve.RVData.SearchText(UpOrDown, MatchCase, WholeWord , WordToFind);

The parameters are only guidance.

For unicodes, there are some complexities in writing the codes.

Hope this is helpful.

Posted: Fri Dec 23, 2005 12:35 pm
by shmp
Forgot to login.

My apology for not being clear to your question earlier. After thinking a while, I believe the only way is to get the ItemText then iterate it to get individual words. Or you can right click to get word at.

Cheers.

Posted: Fri Dec 23, 2005 4:53 pm
by toolwiz
Anonymous wrote:In actual fact there is a simpler way, using rve.RVData.SearchText(UpOrDown, MatchCase, WholeWord , WordToFind);

The parameters are only guidance.

For unicodes, there are some complexities in writing the codes.

Hope this is helpful.
I originally posted my question in an earlier thread that was discussing problems I'm having with SearchText hanging sometimes, but I didn't get any replies. I'm looking for an alternate solution.

Posted: Fri Dec 23, 2005 4:54 pm
by toolwiz
shmp wrote:Forgot to login.

My apology for not being clear to your question earlier. After thinking a while, I believe the only way is to get the ItemText then iterate it to get individual words. Or you can right click to get word at.

Cheers.
I need to have the program iterate through the words. How can the program right-click?

Posted: Fri Dec 23, 2005 5:38 pm
by shmp
I am using rve.RVData.SearchText() and naturally I have to add a lot of traps to prevent my application from hanging. Yea, I had that problem too but I still believe that the SearchText is still the simplest, if the method is for 'search' only.

Posted: Fri Dec 23, 2005 6:45 pm
by toolwiz
shmp wrote:I am using rve.RVData.SearchText() and naturally I have to add a lot of traps to prevent my application from hanging. Yea, I had that problem too but I still believe that the SearchText is still the simplest, if the method is for 'search' only.
Really... what sort of tricks did you use?

Posted: Fri Dec 23, 2005 11:01 pm
by Sergey Tkachenko
I was never informed before about the problems with SearchText.
If you can create a relatively simple project reproducing this problem, please send it to me.

There is, for example, a component in the resources page - a simple syntax highligher that uses the searching function very intensively (its highlighting is based on this search function). If there is some flaw in SearchText, this component would not be possible.

I believe some other code makes it fail, for example, it may fail if you do some changes that make the document unformatted.

There are ways to make words separate items. For example, you can use the class TRVWordEnumerator (from the unit RVWordEnum.pas from http://www.trichview.com/resources/spell/rvspell.zip )
This class calls its method ProcessWord for each word in the document. In this method, you can select this word and apply a different style to it. For example, if all text is initially of the 0-th style, applying the 1-th text style to every word makes them separate items.
You need to create a class inherited from TRVWordEnumerator, like in this example:

Code: Select all

type
  TWordColorer = class (TRVWordEnumerator)
  private
    FEdit: TCustomRichViewEdit;
  public
    procedure Run(Edit: TCustomRichViewEdit);
    function ProcessWord: Boolean; override;
  end;

function TWordColorer.ProcessWord: Boolean;
begin
  // word is available in FWord variable
  SelectCurrentWord;
  FEdit.ApplyTextStyle(1);
  Result := True;
end;
Using: create this class and call its Run method.
But I do not recommend to use this way. And may be the code that causes SearchText to fail will affect to this class as well.

Posted: Fri Dec 23, 2005 11:34 pm
by toolwiz
Ok, thanks Sergey.

Please tell me, when is it necessary to call rve.Format? Does it need to be called any time you change anything in the rve?

Here's what my search loop looks like:

Code: Select all

for wd_ndx := 0 to cklist.Count-1 do begin
   sl := TStringList(cklist.Items.Objects[wd_ndx]);
   if (sl <> nil) then begin
      wd := cklist.Items[wd_ndx];
      rve.SetSelectionBounds(0, rve.GetOffsBeforeItem(0), 0, rve.GetOffsBeforeItem(0));
      while rve.SearchText( wd, [rvseoDown,rvseoWholeWord]) do begin
         if (prev_item_no = rve.CurItemNo) then // sometimes this gets stuck in a loop.  This should help us break out.
            break;

         inc( tot_kwds );
         RVGetSelection( rve, _st, _len );
         n := tagged_wds.AddKwd( wd, _st, _len );
         rve.SetCurrentTag( n );  // lets us lookup entry in tagged_wds
         rve.ApplyTextStyle(2);

         if (prev_item_no <> rve.CurItemNo) then 
            prev_item_no := rve.CurItemNo;
      end;
   end;
end;

Is a call to rve.Format needed after, eg., rve.ApplyTextStyle(2)?

It's curious to me that a search function would have a failure mode based on invisible properties, if that's the case. Because I've had this hang up when the only things I've changed were text styles. The text in the controls is not changing at all, only the visual attributes.

In the latest instance, I need to do a search-and-replace looking for just a few macro tags (eg., %%HEADER%%) and replacing them with a block of text from another RVE control. Still, it did hang once.

I cannot reproduce the behavior where the SearchText hangs. It is intermittent and seems unpredictable to me so far.

Thanks
-David

Posted: Sat Dec 24, 2005 3:19 am
by shmp
I am posting a sample here how I overcame the problem. It is quite complicated and involving other methods. I hope Sergey may be able to see the complications in SearchText.

Code: Select all

 {Search -------------------------------------}
function TForm1.rvSearch : boolean;
var
  pucs, ita, itb, itc, z1, z2, z3, z4 : integer;
  SelectedStr, UniStr : String;
  WdFind, ShowMsg : boolean;

  function rvTextFind : boolean;
  begin
    if rve.RVData.SearchText(FindDlg.sUpOrDown, FindDlg.sMatch,
                           FindDlg.sWholeWord , FindDlg.rvTextStr) then Result := True
    else begin
      Result := False;
      if ReplaceCount = 0 then
          Application.MessageBox(
          'None found for this click      ',  'Search complete',
          MB_OK or MB_ICONEXCLAMATION);
    end;
  end;

begin
  Result := True;
  SkipLang := True; //Avoid current textstyle change
  if CheckUniKey(SearchLangID) then begin //Check if SearchLangID is unicode                                                   
    WdFind := False;
    ShowMsg := False;
    ita := -1;
    itb := -1;
    itc := -1;
    while WdFind = False do begin
      if rvTextFind then begin
        if rve.GetItemStyle(rve.CurItemNo) = rvsTable then begin
          rve.TopLevelEditor.GetSelectionBounds(z1, z2, z3, z4, False);
          SelectedStr := rve.TopLevelEditor.RVData.GetSelText(True);
        end else begin
          rve.GetSelectionBounds(z1, z2, z3, z4, False);
          SelectedStr := rve.RVData.GetSelText(True);
        end;
        UniStr := FindDlg.rvTextUni;
        if (ita = z1) and (itb = z3) and (itc = z4)
        and (SelectedStr <> FindDlg.rvTextUni) then begin
          WdFind := True;
          ShowMsg := True;
        end else begin
          ita := z1;
          itb := z3;
          itc := z4;
          if SelectedStr = FindDlg.rvTextUni then begin
            if rve.GetItemStyle(rve.CurItemNo) = rvsTable then
              pucs := rve.TopLevelEditor.RVData.GetItemStyle(z1)
            else pucs := rve.GetItemStyle(z1);
            //test for unicode then match (only) CharacterSet is good enough!!
            if (RVStyle1.TextStyles[pucs].Unicode)
            and (EnumCharset = RVStyle1.TextStyles[pucs].Charset) then
              WdFind := True
             else WdFind := False;
          end else WdFind := False;
        end;
      end else WdFind := True;
    end;
    if ShowMsg then begin
      rve.Deselect;
      rve.Reformat;
      Application.MessageBox(
                       'None found for this click      ', 'Search complete',
                       MB_OK or MB_ICONEXCLAMATION);
    end;
  end else if rvTextFind then Result := True;
  SkipLang := False;
end;
Some of the boolean like SkipLang is to bypass the OnStyleChange temporarily. The function above worked evertime and never hangs even for Unicode. Instead of formating, I used reformat. I like to know once you have updated the SearchText Sergey.

Thanks.

Posted: Sat Dec 24, 2005 1:47 pm
by Sergey Tkachenko
toolwiz, Format is required after methods marked in the help file as "viewer-style methods". All these methods are introduced in TRichView (and inherited by TRichViewEdit).
There is no need to call Format in your code, ApplyTextStyle does not need it (it is introduced in TRichViewEdit, and marked in the help file as "editing-style method")

Can you send me a simple project reproducing the problem which I can compile and test?