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?