![]() |
#1
|
|||
|
|||
![]()
I have a chunk of code that is searching repeatedly for a given search text. In fact there are three search texts ("Sub ", "Function " and "Property " respectively). I use the same procedure to do the searches, and reset the boundaries of the range I am searching after each search attempt.
What happens is that when I'm searching for "Sub ", or "Function ", the code works exactly as I would have hoped.But when I'm searching for "Property ", it fails, and effectively gets into an infinite loop (not much fun, and a reminder to ALWAYS save any code changes you make, otherwise you might lose them). I've attached the chunk of code (3 procedures) and also a copy of the debug.print output that is created. Code:
Sub CodePrintPass1() ' Build a list of Procedures (Sub and Function procedures). ' Make certain that there as a section break before each procedure. Dim SearchRange As Word.Range Dim DocEnd As Long DocEnd = ActiveDocument.Range.End CurrentProcType = synSUB Set SearchRange = ActiveDocument.Content GoToTopOfSource While Not EndOfSource ' Find the next occurrence of the CurrentProc between the start point and the end of the document Pass1GetNextProc SearchRange SearchRange.End = DocEnd Debug.Print "Next range:", SearchRange.Start, SearchRange.End Wend CurrentProcType = synFUNC Set SearchRange = ActiveDocument.Content GoToTopOfSource While Not EndOfSource Pass1GetNextProc SearchRange SearchRange.End = DocEnd Debug.Print "Next range:", SearchRange.Start, SearchRange.End Wend CurrentProcType = synPROPERTY Set SearchRange = ActiveDocument.Content GoToTopOfSource While Not EndOfSource Pass1GetNextProc SearchRange SearchRange.End = DocEnd Debug.Print "Next range:", SearchRange.Start, SearchRange.End Wend End Sub Function Pass1GetNextProc(rng As Word.Range) As tProcEntry ' Find the next occurrence of the keyword Sub (followed by a space!) ' Discard instances where the word is the end of a token (ThisSub, for example) Dim t As tProcEntry Dim CommentRange As Word.Range Dim IsComment As Boolean t.ProcType = "" ' Indicator that t contains no useful data. With rng.Find .Text = CurrentProcType .Forward = True .Wrap = wdFindStop Debug.Print "Start", rng.Start, rng.End .Execute If .Found Then Debug.Print "Found ", rng.Start, rng.End, rng.Text ' Now see if we are on a comment line Set CommentRange = rng.Duplicate IsComment = Pass1TestForCommentLine(CommentRange) If IsComment Then Debug.Print "Comment", rng.Start, rng.End, rng.Text ' This is a comment line, leave return value undefined and move on to the next word Else ' We have a valid source line. Construct a new tProcType entry Debug.Print "Valid Source", rng.Start, rng.End, rng.Text ' Use CommentRange to get the number of lines between the start of the document and the current ProcType Set CommentRange = rng.Duplicate CommentRange.Start = ActiveDocument.Range.Start ' Move on to the next word, which contains the Name of the current procedure rng.Collapse wdCollapseEnd rng.MoveEnd unit:=wdWord, Count:=1 Debug.Print "ProcName", rng.Start, rng.End, rng.Text With t .ProcType = Trim(CurrentProcType) .Name = rng.Text .StartLine = CommentRange.ComputeStatistics(wdStatisticLines) Debug.Print .ProcType, rng.Start, , .Name, "Line " & .StartLine End With End If ' Collapse the range, then advance by 1 word to get the name of the procedure rng.Collapse wdCollapseEnd Debug.Print "Collapse", rng.Start, rng.End rng.MoveEnd unit:=wdWord, Count:=1 Debug.Print "Move On", rng.Start, rng.End rng.Collapse wdCollapseEnd Debug.Print "Next up", rng.Start, rng.End, rng.Text Else EndOfSource = True Debug.Print "EOF!", rng.Start, rng.End End If Debug.Print End With rng.Select Pass1GetNextProc = t End Function Function Pass1TestForCommentLine(rng As Word.Range) As Boolean ' See if there is a comment character earlier in the line. If so, then this keyword does not ' count as a valid example of CurrentProcType. Dim ch As String While ch <> Chr(13) And ch <> "'" rng.MoveStart unit:=wdCharacter, Count:=-1 ch = Left(rng.Text, 1) ' Debug.Print rng.Start, rng.End, ch, rng.Text Wend If ch = "'" Then Pass1TestForCommentLine = True Else Pass1TestForCommentLine = False End If End Function Code:
Next range: 5463 11702 Start 5463 11702 Found 5496 5500 Sub Valid Source 5496 5500 Sub ProcName 5500 5513 BuildProcList Sub 5500 BuildProcList Line 187 Collapse 5513 5513 Move On 5513 5515 Next up 5515 5515 Next range: 5515 11702 Start 5515 11702 Found 5868 5872 Sub Valid Source 5868 5872 Sub ProcName 5872 5891 zTestOpenSourceFIle Sub 5872 zTestOpenSourceFIle Line 214 Collapse 5891 5891 Move On 5891 5893 Next up 5893 5893 Next range: 5893 11702 Start 5893 11702 Found 11130 11134 Sub Valid Source 11130 11134 Sub ProcName 11134 11138 and Sub 11134 and Line 394 Collapse 11138 11138 Move On 11138 11147 Next up 11147 11147 Next range: 11147 11702 Start 11147 11702 EOF! 11147 11702 Next range: 11147 11702 Start 0 11702 Found 3339 3348 Function Valid Source 3339 3348 Function ProcName 3348 3365 GetSourceFileName Function 3348 GetSourceFileName Line 83 Collapse 3365 3365 Move On 3365 3368 Next up 3368 3368 Next range: 3368 11702 Start 3368 11702 Found 4051 4060 Function Comment 4051 4060 Function Collapse 4060 4060 Move On 4060 4070 Next up 4070 4070 Next range: 4070 11702 Start 4070 11702 Found 4360 4369 Function Valid Source 4360 4369 Function ProcName 4369 4384 Pass1GetNextSub Function 4369 Pass1GetNextSub Line 136 Collapse 4384 4384 Move On 4384 4387 Next up 4387 4387 Next range: 4387 11702 Start 4387 11702 Found 4570 4579 Function Valid Source 4570 4579 Function ProcName 4579 4599 Pass1GetNextFunction Function 4579 Pass1GetNextFunction Line 143 Collapse 4599 4599 Move On 4599 4601 Next up 4601 4601 Next range: 4601 11702 Start 4601 11702 Found 4776 4785 Function Valid Source 4776 4785 Function ProcName 4785 4805 Pass1GetNextProperty Function 4785 Pass1GetNextProperty Line 150 Collapse 4805 4805 Move On 4805 4807 Next up 4807 4807 Next range: 4807 11702 Start 4807 11702 Found 5558 5567 Function Valid Source 5558 5567 Function ProcName 5567 5580 GetModuleName Function 5567 GetModuleName Line 193 Collapse 5580 5580 Move On 5580 5583 Next up 5583 5583 Next range: 5583 11702 Start 5583 11702 Found 5636 5645 Function Valid Source 5636 5645 Function ProcName 5645 5659 GetVersionDate Function 5645 GetVersionDate Line 199 Collapse 5659 5659 Move On 5659 5662 Next up 5662 5662 Next range: 5662 11702 Start 5662 11702 Found 5717 5726 Function Valid Source 5717 5726 Function ProcName 5726 5742 GetVersionString Function 5726 GetVersionString Line 205 Collapse 5742 5742 Move On 5742 5745 Next up 5745 5745 Next range: 5745 11702 Start 5745 11702 Found 11138 11147 Function Valid Source 11138 11147 Function ProcName 11147 11157 procedures Function 11147 procedures Line 394 Collapse 11157 11157 Move On 11157 11159 Next up 11159 11159 Next range: 11159 11702 Start 11159 11702 EOF! 11159 11702 Next range: 11159 11702 Start 0 11702 Found 409 418 PROPERTY Valid Source 409 418 PROPERTY ProcName 418 420 = Property 418 = Line 13 Collapse 420 420 Move On 420 421 Next up 421 421 Next range: 421 11702 Start 421 11702 Found 436 445 PROPERTY Valid Source 436 445 PROPERTY ProcName 445 447 = Property 445 = Line 14 Collapse 447 447 Move On 447 448 Next up 448 448 Next range: 448 11702 Start 448 11702 Found 463 472 PROPERTY Valid Source 463 472 PROPERTY ProcName 472 474 = Property 472 = Line 15 Collapse 474 474 Move On 474 475 Next up 475 475 Next range: 475 11702 Start 475 11702 Found 4853 4862 Property Comment 4853 4862 Property Collapse 4862 4862 Move On 4862 4863 Next up 4863 4863 Next range: 4863 11702 Start 4863 11702 Found 4936 4945 property Comment 4936 4945 property Collapse 4945 4945 Move On 4945 4946 Next up 4946 4946 Next range: 4946 11702 Start 4946 11702 Found 6751 6760 Property Valid Source 6751 6760 Property ProcName 6760 6764 Name Property 6760 Name Line 240 Collapse 6764 6764 Move On 6764 6765 Next up 6765 6765 Next range: 6765 11702 Start 6765 11702 Found 6751 6760 Property Valid Source 6751 6760 Property ProcName 6760 6764 Name Property 6760 Name Line 240 Collapse 6764 6764 Move On 6764 6765 Next up 6765 6765 Next range: 6765 11702 My question is, basically, how come the process of moving on to the next word and extending the range to the end of the document works two out of three times, but fails spectacularly on the third time? The Find object actually goes outside the range, and seems to search backwards(even though it is explicitly set to Forward). Any ideas? Thanks, Tony |
#2
|
||||
|
||||
![]()
Cross-posted at: http://www.excelforum.com/word-programming-vba-macros/
For cross-posting etiquette, please read: http://www.excelguru.ca/content.php?184 It's difficult to see how your code is failing on "Sub ", "Function " and "Property " when none of those expressions appear in your 122 lines of code. Neither is there any indication that you input them from somewhere else. It would also be helpful if you said what you're actually trying to achieve. So far your code etc. basically exists in a contextless vacuum.
__________________
Cheers, Paul Edstein [Fmr MS MVP - Word] |
#3
|
|||
|
|||
![]()
My apologies for obfuscation through minimizing! I tried to clear away any unnecessary detail, but I may have been too exuberant in this effort. To try and answer your points:
1) The values "Sub ",Function " "Property " are in fact the (externally declared) symbolic constants synSub, synFunc and synProperty. Those declarations are as follows: const synSub="Sub " const synFunc="Function " const synProperty="Property " I guess I hoped that the name would be meaningful.It is also what's printed out in the debug statements (as CurrentProcType). 2) What I'm trying to accomplish is, pretty well, what I said. I'm searching a whole bunch of text for these values. I believe that the setting up of the Find object is accurate (in Pass1GetNextProc), and my concern is that the Find seems to fail (as shown in the debug output, where a find operation in a range from 6765 to 11702 seems to produce a result that starts at 6751 - 14 characters outside the specified range. However - between posting (yes, cross-posting mea maxime culpa) and getting your response, I did some more research, and it seems that the Find operation behaves differently when it is inside a table structure. The range which causes the behaviour I noted is indeed in a table cell. So, trying to be more tightly focused on the actual concern, I guess I would restate the problem as: The documentation of the Find object in Word makes no special mention of how it behaves in a table cell. Absent such alert, I believe I have a right to expect that it would behave no differently. The belief is confounded by what actually happens. I can find no way to determine if a range is within a table except by constructing a list of tables (and possibly cells) and testing every single Find operation against that list, and coding it differently when that happens. When I perform the find manually, within the UI of Word itself (Word 365) I get all appearances of the search text, including those within a table. So it seems as Microsoft has no trouble getting past the road-bump that I've encountered. What I'd like to do is to find out exactly how they do this. Now - in the wider context of what I'm trying to do with this code, it doesn't really matter, because the text will be a series of lines with no tables, and all nicely delimited by CR-LF. However, the phenomenom is real, and repeatable, and manifestly it has a work-around (because MS does in fact not encounter the same problem). So, at the moment this is largely of academic interest. However, it's kind of like a $0.25 discrepancy in accounting for CPU usage, which led to the unveiling of all sorts of Cyber attacks. (The Cuckoo's Egg, 1989) Thanks for your feedback, I'd love to know if you can offer any help with this issue. Tony |
#4
|
||||
|
||||
![]()
About the only thing that doesn't work via a Find in tables is when you specify a paragraph break and what you're trying to find has an end-of-cell marker instead - and there's no Find expression for an end-of-cell marker. The code I posted at ExcelForum works just fine with tables otherwise. There are work-arounds for tables; none of them particularly elegant. For example:
Code:
Sub Demo() Application.ScreenUpdating = False Dim i As Long With ActiveDocument.Range With .Find .ClearFormatting .Replacement.ClearFormatting .Text = InputBox("What is the Text to Find") .Replacement.Text = "" .Forward = True .Wrap = wdFindStop .Format = False .MatchCase = False .MatchWholeWord = False .MatchWildcards = False .MatchSoundsLike = False .MatchAllWordForms = False .Execute End With Do While .Find.Found If .Characters.Last.Next = vbCr Then i = i + 1 ElseIf .Information(wdWithInTable) Then .End = .End + 1 If .Characters.Last = .Cells(1).Range.Characters.Last Then i = i + 1 End If .Collapse wdCollapseEnd .Find.Execute Loop End With Application.ScreenUpdating = True MsgBox i & " instances found." End Sub
__________________
Cheers, Paul Edstein [Fmr MS MVP - Word] |
![]() |
Thread Tools | |
Display Modes | |
|
![]() |
||||
Thread | Thread Starter | Forum | Replies | Last Post |
![]() |
LaC0saNostra | Word | 2 | 02-01-2015 11:35 AM |
![]() |
ep2002 | Excel | 1 | 07-27-2014 06:53 PM |
Accent symbols not working properly on new computer | Binary.tobis | Excel | 3 | 04-28-2012 04:49 PM |
![]() |
pajkul | Publisher | 1 | 01-23-2011 07:51 PM |
Word 2000 Macro not working properly | brianlb | Word VBA | 1 | 07-01-2009 07:04 AM |