[RESOLVED] Out of Stack String Space - RichTextBox
I have a search routine which looks for certain words or phrases in a RichTextBox. When searching within a 'larger' (but not REALLY large) RTB, I am getting the following error: Out of stack string space. Using the same RTB with fewer occurrences, I do not not experience this. But when searching (and wanting to count) for a certain word (that word should appear around 4500 times in the RTB). The RTB contains around 605,000 characters (not all that huge). But when I attempt the following code to get the exact number of occurrence of that word in the RTB, I get that error on the line bolded in Red:
Code:
Private Function FindIt(Box As RichTextBox, Srch As String, Optional start As Long) Dim retval As Long
Dim Source As String
Source = UCase(Box.Text)
If start = 0 Then start = 1
retval = InStr(start, Source, Srch)
If retval <> 0 Then
With Box
.SelStart = retval - 1
.SelLength = Len(Srch)
.SelColor = vbRed
.SelBold = True
.SelLength = 0
End With
start = retval + Len(Srch)
FindIt = 1 + FindIt(Box, Srch, start)
End If
End Function
I don't see anything I'd call a memory leak. However, I do see recursion. With recursion, it's always good to recognize how much memory you're using with your variables. As your function stands, all the variables you used are using additional memory on each recursion.
You're passing all your arguments as ByRef, but you're still using an additional memory pointer on the stack for each recursive call.
And, regarding retval and Source, you're creating a separate copy on each recursive call. Actually, it's probably that Source variable that's causing most of your problems. The way you're using it, there's no need to make separate copies on each recursive call. Just make it a module-level variable, and you'll probably solve your problem.
You could also do the same with retval, and also possibly some of the arguments (such as Box), and your function will still run just fine. From a casual look, it seems that only start needs to be passed on each recursion.
Good Luck,
Elroy
EDIT1: Actually, if you're reluctant to make anything module-level, just clearing that Source variable just before you recurse may also solve your problems. You're done with it at that point:
Code:
Source = vbNullString ' <----- New code line !!!
FindIt = 1 + FindIt(Box, Srch, start)
Last edited by Elroy; Jul 9th, 2019 at 08:56 AM.
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
@ Elroy....declaring source in module resulted in a simple crash of the program...no error even given. And setting it to vbNullString actually made no difference...crashed program with no given error.
If you're expecting over 4000 matches, that means your pushing over 4000 sets of variables on the stack, and then you have to unwind all those pushes on the stack as well.
I really don't see a reason this should be a recursive function, as it is wasteful for this purpose.
Just do a loop in the function to find all the values.
Code:
Private Function FindIt2(Box As RichTextbox, Srch As String, Optional start As Long)
Dim retval As Long
Dim Source As String
Dim Count As Long
Source = UCase(Box.Text)
If start = 0 Then start = 1
retval = InStr(start, Source, Srch) 'find the first match
Do While retval <> 0
Count = Count + 1
With Box
.SelStart = retval - 1
.SelLength = Len(Srch)
.SelColor = vbRed
.SelBold = True
.SelLength = 0
End With
start = retval + Len(Srch)
retval = InStr(start, Source, Srch) 'look for additional matches
Loop
FindIt2 = Count
End Function
Dim numOccurences As Double
numOccurences = FindIt(frmSearchResults.rtb1, UCase$(frmSearchResults.rtb1.Text), UCase(Text2.Text), 1)
Function: NOTE: I commented out highlight code temporarily
Code:
Private Function FindIt(Box As RichTextBox, Source As String, Srch As String, Optional start As Long) Dim retval As Long
If start = 0 Then start = 1
retval = InStr(start, Source, Srch)
If retval <> 0 Then
' With Box
' .SelStart = retval - 1
' .SelLength = Len(Srch)
' .SelColor = vbRed
' .SelBold = True
' .SelLength = 0
' End With
start = retval + Len(Srch)
FindIt = 1 + FindIt(Box, UCase$(frmSearchResults.rtb1.Text), Srch, start)
End If
End Function
I get an OUT OF MEMORY Error on the bolded red line (recursive portion).
@ passel....your suggestion next
Last edited by SamOscarBrown; Jul 9th, 2019 at 09:43 AM.
Reason: misspelled 'your'
@ passel....yup...that worked fine. Found the 4531 occurrences of the search word in the 3910 lines of the RTB.
Appreciate the advice to not use a recursive function...had thought it necessary when I first built this thing about 8 years ago.
But, at LaVolpe and Elroy...would still like to determine why the recursive functions (as shown previously) errored or crashed, in case I want to use something similar in the future.
I get an OUT OF MEMORY Error on the bolded red line (recursive portion).
Yep, you didn't understand what I was trying to say & I didn't explain it well enough.
I know you have this resolved, but I just wanted to update the thread for future use (if any). Changes in blue
Code:
Dim numOccurences As Double
numOccurences = FindIt(frmSearchResults.rtb1, UCase$(frmSearchResults.rtb1.Text), UCase(Text2.Text), 1)
Function: NOTE: I commented out highlight code temporarily
Code:
Private Function FindIt(Box As RichTextBox, Source As String, Srch As String, Optional start As Long) Dim retval As Long
If start = 0 Then start = 1
retval = InStr(start, Source, Srch)
If retval <> 0 Then
' With Box
' .SelStart = retval - 1
' .SelLength = Len(Srch)
' .SelColor = vbRed
' .SelBold = True
' .SelLength = 0
' End With
start = retval + Len(Srch)
FindIt = 1 + FindIt(Box, Source, Srch, start)
End If
End Function
Insomnia is just a byproduct of, "It can't be done"
In the case above, you're creating a uppercase version of your text string for each recursive call.
You said you had about 605,000 characters, so assume that is 1,210,000 bytes per call.
You need to call the routine 4531 times, so 4531 * 1,210,000 = 5,482,510,000 bytes of memory (about 5.5 GB).
Since VB6 normally only has a 2GB executable address space, you have a fair amount less than 2GB space available for Strings, so you run out of memory long before you can call the routine the number of times required.
A recursive routine normally acts on some external data repeatedly, so the values preserved on the stack for each recursive call is fairly small, usually just pointers, counters, and status type variable that keep track of what is being processed at each level.
Recursion is good for traversing a hierarchy, like calculating moves, or paths, etc...
In your case, you're doing a straight forward linear search of a large string, so real benefit to having it a recursive function as there are no conditional branches and other paths to explore. No reason to keep a history of your search values in order to unwind to an earlier level and take a different direction.
{edit}
Since LaVolpe has already explained what he meant, I've removed that from this post.
With that change, you now only create the string once, and you are passing a reference to that string (the same way you're passing a reference to the textbox) with each call, so instead of a million+ bytes per call, you are only adding a small amount of bytes per call (whatever a reference for a string is, which may just be a 4 byte pointer to a string structure, which points to the string).
That would still mean 4 * 4531 bytes used by the recursive process for that parameter, and the same for the textbox parameter, but at least that is very manageable, although an unnecessary overhead without any benefit in this case.
Re: [RESOLVED] Out of Stack String Space - RichTextBox
@ LaVolpe....re-tried what you suggested. Crashed program (because of what passel is saying, I am sure). You explained it fine the first time...I just didn't pay attention. I called the function the first time properly, but in the recursive section, I simply copied the UCASE$ thingy instead of using Source (duh---just wasn't thinking).
@passel...understand. That IS a fair amount of memory usage! Your explanation is back to the basics I should have recalled from years ago, but didn't.
So, if I don't keep a history of search values each time in a recursive function, how do I do that? I thought Elroy's suggestion setting Source to vbNullString would have done it.
Re: [RESOLVED] Out of Stack String Space - RichTextBox
I'm probably not testing quite as much text as you are, Sam ... but just setting Source to vbNullString works for me.
I also declared your FindIt function as a Long rather than letting it default to Variant.
My test is attached.
EDIT1: I also searched for "A" rather than "AND". It found 1212 occurrences, but still worked just fine.
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
Re: [RESOLVED] Out of Stack String Space - RichTextBox
Originally Posted by SamOscarBrown
...
So, if I don't keep a history of search values each time in a recursive function, how do I do that? I thought Elroy's suggestion setting Source to vbNullString would have done it.
I don't know when the data associated with a reference is cleaned up in VB6.
The UCase function should create a large string in memory, then return a reference to it, which you assign to Source.
Later, you set Source to vbNullString, so you've disconnected the reference to the large string.
Since the large string should no longer have any variable referencing it, it should probably be "cleaned up", and the memory recovered, but I don't know when that occurs. It might be something that is done between user code events, i.e. once you leave a sub, housekeeping chores are run, and objects without references are disposed of.
Since you didn't leave the sub, but had the sub call itself, then I can imagine that the unreferenced string is still there, but "flagged" for disposal. So, although you set your reference to the string to 0, it isn't getting rid of the string itself yet, so you eventually end up crashing in yet another way, which perhaps doesn't trigger the Out of Memory exception because of the nature of the error, although it seems like it should.
Mostly supposition on my part, not a known fact.
p.s. I can't look at Elroy's test because I'm at work and I'm blocked from downloading from the site, but I suspect that Elroy's string might be short enough, that it doesn't run out of memory before the recursion is complete, and then as each level of recursion exits it's sub, the string memory is recovered from each of those levels because of the string reference having been set to vbNullString.
Again, a supposition, no testing done.
Re: [RESOLVED] Out of Stack String Space - RichTextBox
I'll 'gin' up an exportable example (using the recursion function I started with)...and if it still crashes the program, I'll post it. I'll then try it with Elroy's code (but with my rtb data) and see.
@passel...that certainly makes some sense...that is, when a reference is 'cleaned up'.
Re: [RESOLVED] Out of Stack String Space - RichTextBox
What Passel outlines sounds more like managed code. I'll admit that I'm not totally sure how memory is managed for VB6 (or any COM based 32-bit application), but I'm under the impression that things are done immediately (such as instantiation/un-instantiation, memory requests, memory releases, and the like). In other words, when memory is to be released, our thread doesn't continue until that task is completed.
It's always been a puzzle to me how holes in memory are eventually squashed, but maybe they're not. Or maybe Windows just keeps track of things in a way that just fills them whenever something else will fit into them. I'd be delighted if someone else would outline that a bit more.
Also, every time I say the words "garbage collector" (like we had in the old DOS days), I get pounced on.
I do know that nothing seems to move around in memory, allowing us to trust our memory pointers for extended periods of time. So, I'm not totally sure.
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
Re: [RESOLVED] Out of Stack String Space - RichTextBox
Hi Sam,
another option may be using Regex, the File I used had 55080 words and the find was 2214
here the sample
Code:
Option Explicit
Private pRegEx As Object
Public Property Get oRegex() As Object
If (pRegEx Is Nothing) Then
Set pRegEx = CreateObject("Vbscript.Regexp")
End If
Set oRegex = pRegEx
End Property
Public Function ReadFile(ByRef Path As String) As String
Dim FileNr As Long
On Error Resume Next
If FileLen(Path) = 0 Then Exit Function
On Error GoTo 0
FileNr = FreeFile
Open Path For Binary As #FileNr
ReadFile = Space$(LOF(FileNr))
Get #FileNr, , ReadFile
Close #FileNr
End Function
Private Sub Command1_Click()
'the file has 55080 words and found 2214
RichTextBox1.Text = ReadFile("E:\book04.txt")
End Sub
Private Sub Command2_Click()
Dim oRegex As Object
Dim m As Object
Dim strPattern As String
Dim i As Long
strPattern = " and " '<- the word to find, notice space before/after the word
If Len(Trim(strPattern)) = 0 Then Exit Sub
On Error GoTo ErrHandler
'set color to Black
With RichTextBox1
.SelStart = 1
.SelLength = Len(.Text)
.SelColor = vbBlack
End With
' "Regular-Expression"-Objekt
Set oRegex = CreateObject("VBScript.RegExp")
With oRegex
.Pattern = strPattern
.Global = True
' --> go threw all matches
i = 0
For Each m In .Execute(RichTextBox1.Text)
' --> found items to Red
With RichTextBox1
.SelStart = m.FirstIndex
.SelLength = m.Length
.SelColor = vbRed
End With
'--> Counter
i = i + 1
Next
End With
Text1.Text = "the Count is : " & i
' --> kill Regex Object
Set oRegex = Nothing
Set m = Nothing
Exit Sub
ErrHandler:
MsgBox Err.Description & vbCrLf & Err.Number, vbCritical + vbOKOnly, "Error"
Err.Clear
End Sub
hth
to hunt a species to extinction is not logical !
since 2010 the number of Tigers are rising again in 2016 - 3900 were counted. with Baby Callas it's 3901, my wife and I had 2-3 months the privilege of raising a Baby Tiger.
Re: [RESOLVED] Out of Stack String Space - RichTextBox
Using UCase$() on a large text value can have both benefits and limitations.
It can be faster to do a case-insensitive search on but...
First you eat twice the memory by having two copies around.
Second you lose all of the advantages of orthography-sensitive comparisons, for example handling ligature and digraph comparisons properly.
I'm not sure there is any version of regex smart enough to do the job properly. They are simple tools meant to help in slow and clunky shell scripting languages, not something a real compiled program would ever use.
Re: [RESOLVED] Out of Stack String Space - RichTextBox
Ok, some more thoughts on all of this.
First, the .Text property of the RTB is already a String:
It's not clear if that's a function returning a string that's built each time the function is called, or possibly a string that already exists inside the RTB code. If it already exists, then just directly using that .Text property would be better than copying it before we use it. However, that'd take some timing tests to figure out. (Basically, we'd just need to test a simple InStr with a string versus InStr with a RTB.Text, both in loops to build enough time to be meaningful.)
------
And second, if we're willing to use the SHLWAPI.DLL library, rather than VB6's InStr, it seems that we could do ourselves some large favors:
Code:
'
' https://docs.microsoft.com/en-us/windows/win32/api/shlwapi/nf-shlwapi-strstrw
Private Declare Function StrStrW Lib "SHLWAPI" (ByVal lpFirst As Long, ByVal lpSrch As Long) As Long ' Case sensitive.
'
' https://docs.microsoft.com/en-us/windows/win32/api/shlwapi/nf-shlwapi-strstriw
Private Declare Function StrStrIW Lib "SHLWAPI" (ByVal lpFirst As Long, ByVal lpSrch As Long) As Long ' NOT case sensitive.
'
We'd want to make sure to use the ...W versions of the calls so we're not making yet more copies of our string. But, by adding offsets to lpFirst, we could effectively accomplish the same thing that the start argument to InStr is accomplishing. It doesn't seem that it would take that much to develop a nice case-insensitive InStr alternative.
Just Spit-Balling,
Elroy
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
Re: [RESOLVED] Out of Stack String Space - RichTextBox
The Text property value has to be manufactured each time it is called.
InStr already has the vbTextCompare option. It looks like this is one place where you can provide a valid LCID as the option to get text comparison using the rules of that locale instead of the user's locale.
Last edited by dilettante; Jul 10th, 2019 at 10:07 AM.
Re: [RESOLVED] Out of Stack String Space - RichTextBox
Actually, looking at the OP code, Sam, you'd certainly be doing yourself a favor if you replaced the...
Code:
retval = InStr(start, Source, Srch)
... line of code with ...
Code:
retval = InStr(start, UCase(Box.Text), Srch)
... and then eliminate the Source variable altogether. That way, the string passed into InStr is just a VB6 temp string that VB6 will clean-up. And it will almost certainly reduce the thrashing of memory at least a bit.
I might still do more testing on my ideas in my last post.
Best Regards,
Elroy
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
Re: [RESOLVED] Out of Stack String Space - RichTextBox
Originally Posted by Elroy
And second, if we're willing to use the SHLWAPI.DLL library, rather than VB6's InStr, it seems that we could do ourselves some large favors:
Code:
'
' https://docs.microsoft.com/en-us/windows/win32/api/shlwapi/nf-shlwapi-strstrw
Private Declare Function StrStrW Lib "SHLWAPI" (ByVal lpFirst As Long, ByVal lpSrch As Long) As Long ' Case sensitive.
'
' https://docs.microsoft.com/en-us/windows/win32/api/shlwapi/nf-shlwapi-strstriw
Private Declare Function StrStrIW Lib "SHLWAPI" (ByVal lpFirst As Long, ByVal lpSrch As Long) As Long ' NOT case sensitive.
'
We'd want to make sure to use the ...W versions of the calls so we're not making yet more copies of our string. But, by adding offsets to lpFirst, we could effectively accomplish the same thing that the start argument to InStr is accomplishing. It doesn't seem that it would take that much to develop a nice case-insensitive InStr alternative.
Just Spit-Balling,
Elroy
StrStrI probably only considers US English, but I am not sure, so it may not have the same behavior as InStr(vbTextCompare).
Re: [RESOLVED] Out of Stack String Space - RichTextBox
Originally Posted by dilettante
The Text property value has to be manufactured each time it is called.
I'll test in just a moment.
Originally Posted by dilettante
InStr already has the vbTextCompare option. It looks like this is one place where you can provide a valid LCID as the option to get text comparison using the rules of that locale instead of the user's locale.
I haven't messed with vbTextCompare, but that doesn't give us case-insensitivity, does it?
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
Re: [RESOLVED] Out of Stack String Space - RichTextBox
Ok, based on that information, Sam, the following is a pretty big improvement on your original function:
Code:
Private Function FindIt(Box As RichTextBox, Srch As String, Optional start As Long) As Long
Dim retval As Long
'
If start = 0 Then start = 1
retval = InStr(start, Box.Text, Srch, vbTextCompare)
If retval <> 0 Then
With Box
.SelStart = retval - 1
.SelLength = Len(Srch)
.SelColor = vbRed
.SelBold = True
.SelLength = 0
End With
start = retval + Len(Srch)
FindIt = 1 + FindIt(Box, Srch, start)
End If
End Function
Notice that the Source variable and the call to UCase$() are both gone. This eliminates a considerable amount of memory thrashing. I'm still calling Box.Text on each recursion, but you were already doing that. In a moment, I'll do a timing test to see how much of a speed-penalty we're taking for multiple calls to Box.Text. If they're severe, an alternative would be to make your Source variable a module-level variable, set it before calling FindIt, and then use this module-level variable within FindIt. But again, I'll test.
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
Re: [RESOLVED] Out of Stack String Space - RichTextBox
Hi,
I'll have another go
Code:
Private Sub Command6_Click()
Text1.Text = CountStringInString(RichTextBox1.Text, " and ", False)
End Sub
Public Function CountStringInString(Text As String, SearchFor As String, _
Optional ComapareAsText As Boolean = False) As Long
Dim i As Long, j As Long, z As Long
Dim s As String, s1 As String
If ComapareAsText Then
s = UCase$(Text)
s1 = UCase$(SearchFor)
Else
s = Text
s1 = SearchFor
End If
i = 1
Do
j = InStr(i, s, s1, vbBinaryCompare)
If j = 0 Then
Exit Do
End If
With RichTextBox1
.SelStart = j - 1
.SelLength = Len(s1)
.SelColor = vbRed
.SelBold = True
.SelLength = 0
End With
i = j + Len(s1)
z = z + 1
Loop
CountStringInString = z
End Function
to hunt a species to extinction is not logical !
since 2010 the number of Tigers are rising again in 2016 - 3900 were counted. with Baby Callas it's 3901, my wife and I had 2-3 months the privilege of raising a Baby Tiger.
Re: [RESOLVED] Out of Stack String Space - RichTextBox
Originally Posted by dilettante
I don't know what he wants to search but it seems like the last time this came up it was a 5MB to 7MB Christian Bible stored on disk as ANSI RTF.
I just can't see how it makes sense extract this as a Unicode String over and over again. Why would you even think so?
I think he wan't to load the File into a RTB and mark his search Item RED, or I got the question wrong ?
to hunt a species to extinction is not logical !
since 2010 the number of Tigers are rising again in 2016 - 3900 were counted. with Baby Callas it's 3901, my wife and I had 2-3 months the privilege of raising a Baby Tiger.
Re: [RESOLVED] Out of Stack String Space - RichTextBox
the search isn't the problem, he want's to set Colors in the RTB,for all I know there could/will be more than one word
to search with diffrent Colors
to hunt a species to extinction is not logical !
since 2010 the number of Tigers are rising again in 2016 - 3900 were counted. with Baby Callas it's 3901, my wife and I had 2-3 months the privilege of raising a Baby Tiger.
Re: [RESOLVED] Out of Stack String Space - RichTextBox
Ok, we clearly don't want to call Box.Text over and over:
We take ~100 fold hit for calling the Box.Text property over and over, as opposed to just calling it once and setting it in a string.
I've attached my timing test program. But basically, the loops look something like this:
Code:
Private Sub Command1_Click()
Dim dStringTime As Double
Dim dTextPropTime As Double
dStringTime = TestWithString
dTextPropTime = TestWithTextProp
MsgBox "String time: " & Format$(dStringTime, "0.00000000") & vbCrLf & _
"Text prop time: " & Format$(dTextPropTime, "0.00000000")
End Sub
Private Function TestWithString() As Double
Dim dStart As Double
Dim dFinish As Double
Dim i As Long
Dim j As Long
'
dStart = TimerEx
For i = 1 To LoopIterations
j = InStr(100, s, "and")
Next
dFinish = TimerEx
'
TestWithString = dFinish - dStart
End Function
Private Function TestWithTextProp() As Double
Dim dStart As Double
Dim dFinish As Double
Dim i As Long
Dim j As Long
'
dStart = TimerEx
For i = 1 To LoopIterations
j = InStr(100, RichTextBox1.Text, "and")
Next
dFinish = TimerEx
'
TestWithTextProp = dFinish - dStart
End Function
Therefore, sticking with the OP's recursion theme, we could further improve with something like the following:
Code:
Private Function FindIt(Box As RichTextBox, Srch As String, Optional Start As Long) As Long
Dim Retval As Long
Static Source As String
'
If Start = 0& Then
Source = Box.Text ' Only call Box.Text on our first time in.
Start = 1&
End If
'
Retval = InStr(Start, Source, Srch, vbTextCompare) ' We use vbTextCompare to be case insensitive.
If Retval <> 0 Then
With Box
.SelStart = Retval - 1&
.SelLength = Len(Srch)
.SelColor = vbRed
.SelBold = True
.SelLength = 0&
End With
Start = Retval + Len(Srch)
FindIt = 1& + FindIt(Box, Srch, Start)
End If
End Function
I also cleaned up more of the indentation.
Sticking with the recursion, I think that's about as good as it gets.
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
Re: [RESOLVED] Out of Stack String Space - RichTextBox
Hmmm...just took a break from digging up several old tree stumps in a dried up lake bed, now getting ready to mow 3 acres...so decided to 'check in'.
Very interesting comments and code (although I haven't yet had the time to 'play'). But to clarify a bit...
Yes, my 'Bible' program (I have several versions in an Access Database) is what includes that function. I allow a search routine based on A word, AN exact Phrase, and a Phrase with wildcards. Options to search are the entire Bible (one version at a time), the OT, the NT, the current BOOK being viewed, and the current CHAPTER being viewed. It works well when the number of occurrences is not very large. But when one searches for 'God' (or 'god'---I do not distinguish for capitalization) in an ENTIRE Bible, the program crashed (until I used the code provided by passel). The reason I know how many occurrences should have been id'd, is because I successfully (with the old function) searched both testaments separately.
I am NOT concerned with the amount of time it takes to do the searches.
I use the RTB to display in RED the searched for word or phrase to display to the user. (I also have copy-paste functions to capture Scripture(s) from the RTB).
I hope that answers all the questions above. I am certain there are other methods of doing this, but that is what I put together a few years ago...Just now getting around to allowing searches that return a lot of occurrences.
Well, off to the Husqvarna! Back to this tomorrow....Church tonight.
Re: [RESOLVED] Out of Stack String Space - RichTextBox
Rain started. Got a minute or two. Elroy, substituted "Box.Text" in lieu of 'Source"---only found one occurrence in my 'God search'.
So, to better explain, maybe, I ALREADY have all the Scriptures added to the RichTextBox by a query to my tables based upon if the search word/phrase is found within the Scripture. All I really want to do then is search the RTB for the occurrences and set them Bold Red. That's all.
Dinner is ready, so will look at some of your suggestions tomorrow or late tonight.
Re: [RESOLVED] Out of Stack String Space - RichTextBox
I'm positive we have been down this very same road before. In fact I found the old solution I had proposed. I'm surprised nobody has even suggested this approach in this new thread. It's pretty basic to the RTB and well documented.
Here's a rewrite from scratch, with a sample file included. It makes use of the RTB's Find method and a simple loop:
Note that within paragraphs (no hard line-break) it can find phrases that wrap when printed or displayed. If you have broken things up into lines for some reason you're screwed. The paragraph break causes mismatches for those cases.
Since we didn't retain a "record" of each hit on the search text we must call Find again to step to the next, next, next hit. We must also Find again to "reset." If you retain a log of the position of each hit in an array or something "next" and "reset" could be quicker.
If performance really is an issue (if you search for a word or phrase that occurs a lot search/reset can slow down a lot) using TOM instead of the RTB.Find might be a little quicker. But most of the performance issues seem to come from inserting formatting, not so much searching.
Last edited by dilettante; Jul 11th, 2019 at 02:17 PM.
Re: [RESOLVED] Out of Stack String Space - RichTextBox
dile...I am sure we've traveled along this path in the past...but at my age, who can remember? MAYBE we did discuss this long ago with this exact same problem. And if so, I obviously didn't implement anyone's suggestions.
As far as 'lines', I have each individual verse on a line in the RTB, put there by a query to my DB, i.e. the query finds every verse that has the search word in it and adds it to the RTB. Hence, no need to worry about 'wrapping'. When searching for "God", for example, my query returns 3910 verses. So, once they are in the RTB, I use that 'find' function just to 're-find' the word/phrase so I can highlight and embolden it. And, in those 3910 verses (in the Bible version I am doing my testing with), finds 'God' 4531 times.
I haven't yet downloaded your example, but will do that in next couple of days. (I may also have somewhere on this computer an example you may have posted in one of my threads concerning the RTB find method.)
After typing this little explanation, I wonder if, seeing as how my db query already found the verses with the search word, would there be a way WHEN I ADD THE VERSE TO THE RTB, to, at that point, bold and highlight the search word...that would preclude having to once again search the RTB.
Again, performance, at this point, is not an issue. Yes, it takes a few seconds in MY search routine, but it doesn't matter---it is MY personal program for my personal use.
And as always, to you dile, and all the other helpful folks out there, thanks for taking the time to TRY to 'teach an old dog new tricks'.
Re: [RESOLVED] Out of Stack String Space - RichTextBox
Well my small contribution was really just to consider the RTF.Find method.
If each verse retrieved is just plain text with no RTF markup in it I suppose you might use InStr and friends to find target text occurrences and wrap them in markup text to create an RTF "scrap" that can be appended using the RTB.SelRTF property. I'm not sure what the advantage might be though. It seems like more work.
Re: [RESOLVED] Out of Stack String Space - RichTextBox
I think dilettante is right with the RTF.Find method, but if you(sam) say, the few seconds more, it takes for
the search doesn' matter ... it's up to you
to hunt a species to extinction is not logical !
since 2010 the number of Tigers are rising again in 2016 - 3900 were counted. with Baby Callas it's 3901, my wife and I had 2-3 months the privilege of raising a Baby Tiger.
Re: [RESOLVED] Out of Stack String Space - RichTextBox
Thx both...yeah, time doesn't matter. I WILL try the .Find method shortly. Will report back on success/stupidity on my part/better or worst, etc.
If this were a commercial product, I'd spend a LOT more time studying various methods, options and tools to make it work faster (and correctly, of course), but seeing as how it is just for my use (or maybe a friend's), I'll not spend much more on it....after looking at the .Find method of the RTB.
Re: [RESOLVED] Out of Stack String Space - RichTextBox
RTB.Find is pretty fast actually. Take my demo above and alter it:
Code:
Private Sub cmdSearch_Click()
Dim SearchAt As Long
MousePointer = vbHourglass
With txtSearchFor
.Enabled = False
SearchFor = .Text
End With
HitCount = 0
With rtbText
.Visible = False
Do
SearchAt = .Find(SearchFor, SearchAt, , rtfWholeWord)
If SearchAt < 0 Then Exit Do
SearchAt = SearchAt + Len(SearchFor)
HitCount = HitCount + 1
' .SelColor = vbRed
' .SelBold = True
Loop
.SelStart = 0
If HitCount = 0 Then
lblStatus.Caption = "Found 0 occurrences"
Else
'Bring first hit into view by finding it again:
NextSrearchAt = .Find(SearchFor, 0, , rtfWholeWord) + Len(SearchFor)
HitNumber = 1
lblStatus.Caption = "1 of " & Format$(HitCount, "#,##0") _
& " occurrence" & IIf(HitCount = 1, vbNullString, "s")
If HitCount > 1 Then
cmdNextHit.Enabled = True
cmdNextHit.SetFocus
End If
End If
.Visible = True
End With
cmdReset.Enabled = True
cmdSearch.Enabled = False
MousePointer = vbDefault
End Sub
Now it won't try to highlight the hits and it zips right along by comparison. Choose something common like "and" to search for. The more hits the longer things take.
Searching isn't really the performance problem, inserting and removing the RTF markup takes far longer in the unaltered version of the program.