MS Office Forum / Word / Programming / April 2006
Number of Finds and Replaces
|
|
Thread rating:  |
Ricardo Muiz - 14 Apr 2006 02:21 GMT I know I've seen this posted before but...
I'm trying to find a quick way to count the number of word's occurences within a document. The Find method can be slow. What I really want is the information from the Find and Replace dialog message through the user interface (something like "This or that has been replaced 993 times"). How can get hold of the text from that message?
Jay Freedman - 14 Apr 2006 03:37 GMT See http://word.mvps.org/FAQs/MacrosVBA/NoTimesTextInDoc.htm -- I think that's what you're referring to as "the Find method".
Another scheme is to (a) get the value of ActiveDocument.Words.Count, (b) do a ReplaceAll to replace the word being counted with "" (that is, delete all occurrences), (c) get the new value of ActiveDocument.Words.Count and subtract it from the original count to get the number of replacements, and (d) run Undo to put the words back.
A third scheme is to assign ActiveDocument.Range.Text to a string variable, and iterate the InStr method over it (using the optional first argument to move the starting position each time).
I'll leave it to you to find out which is fastest in your application.
-- Regards, Jay Freedman Microsoft Word MVP FAQ: http://word.mvps.org Email cannot be acknowledged; please post all follow-ups to the newsgroup so all may benefit.
>I know I've seen this posted before but... > [quoted text clipped - 3 lines] >interface (something like "This or that has been replaced 993 times"). How >can get hold of the text from that message? Greg Maxey - 14 Apr 2006 03:53 GMT Jay,
Is something like this what you had in mind by method 3?
Sub Test() Dim oString As String oString = ActiveDocument.Range.Text Dim i As Long Dim j As Long i = 1 While InStr(i, oString, "now") <> 0 i = InStr(i, oString, "now") + 1 j = j + 1 Wend MsgBox j End Sub
 Signature Greg Maxey/Word MVP See: http://gregmaxey.mvps.org/word_tips.htm For some helpful tips using Word.
> See http://word.mvps.org/FAQs/MacrosVBA/NoTimesTextInDoc.htm -- I > think that's what you're referring to as "the Find method". [quoted text clipped - 20 lines] >> been replaced 993 times"). How can get hold of the text from that >> message? Jezebel - 14 Apr 2006 05:04 GMT Simpler would be a version of the second method: use Replace to remove all instances of the string, then divide then change in length by the length of the word.
pLenBefore = len(oString) oString = Replace(oString, SearchWord, "") pLenAfter = len(oString) pCount = (pLenBefore - pLenAfter) / len(SearchWord)
In both cases (this method and your original) you'd need to defend against the possibility of the search word being a substring of another word.
> Jay, > [quoted text clipped - 37 lines] >>> been replaced 993 times"). How can get hold of the text from that >>> message? Helmut Weber - 14 Apr 2006 04:13 GMT Hi Ricardo,
http://word.mvps.org/FAQs/MacrosVBA/GetNoOfReplacements.htm
If you want to use the dialog, how about this rather unusual solution, as there seems always to be an error in editreplace, because the last attempt of replacing fails, and the message displayed after the replacement is the error description.
One thing I couldn't manage, was to put the find-string in the message, like:
"quick" was found x times.
Maybe somebody else will find a way. <<<
Sub test() Dim ss As String ' short string, the number of replacements Dim sl As String ' long string, the error message Dim l As Long ' just a loop variable Dim oDlg As Dialog
ActiveDocument.Range(0, 0).Select Selection.ExtendMode = False ResetSearch
Set oDlg = Dialogs(wdDialogEditReplace) On Error Resume Next oDlg.Display sl = Err.Description ' in localized versions you don't know ' where the number of replacements occurs in the text For l = 1 To Len(sl) If IsNumeric(Mid(sl, l, 1)) Then ss = ss & Mid(sl, l, 1) End If Next MsgBox " Found: " & ss & " times" ResetSearch End Sub
 Signature Greetings from Bavaria, Germany
Helmut Weber, MVP WordVBA
Win XP, Office 2003 "red.sys" & Chr$(64) & "t-online.de"
Helmut Weber - 14 Apr 2006 04:15 GMT Public Sub ResetSearch() With Selection.Find .ClearFormatting .Replacement.ClearFormatting .Text = "" .Replacement.Text = "" .Forward = True .Wrap = wdFindContinue .Format = False .MatchCase = False .MatchWholeWord = False .MatchWildcards = False .MatchSoundsLike = False .MatchAllWordForms = False .Execute End With End Sub
Ricardo Muiz - 14 Apr 2006 05:21 GMT I like Helmut's approach - almost.
Unconventional is one thing but, first, it seems to rely on a bug. Not that Microsoft would ever fix it. Second, the user has to see dialogs popping up each time (apparently even if you hide the application). This can be fixed by using the .Execute method. However, that does not return an error (Err.Number = 0) so there is no string to parse and I'm back to the original problem.
For completeness, here's some code to make it run automatically. Helmut did the clever work, I added the SendKeys.
Sub test() Dim ss As String ' short string, the number of replacements Dim sl As String ' long string, the error message Dim l As Long ' just a loop variable Dim oDlg As Dialog
ActiveDocument.Range(0, 0).Select Selection.ExtendMode = False 'ResetSearch
Set oDlg = Dialogs(wdDialogEditReplace) On Error Resume Next oDlg.Find = "a" oDlg.Replace = "X" oDlg.ReplaceAll = True SendKeys "%a" 'This also relys on this dialog not changing in a subsequent release. SendKeys "{tab}" SendKeys "{tab}" SendKeys "{tab}" SendKeys "{enter}" oDlg.Display 'oDlg.Execute sl = Err.Description ' in localized versions you don't know ' where the number of replacements occurs in the text For l = 1 To Len(sl) If IsNumeric(Mid(sl, l, 1)) Then ss = ss & Mid(sl, l, 1) End If Next ActiveDocument.Undo 'ResetSearch MsgBox " Found: " & ss & " times" End Su
> Hi Ricardo, > [quoted text clipped - 38 lines] > ResetSearch > End Sub Greg Maxey - 14 Apr 2006 05:48 GMT Hmm.... by adding *:
oDlg.ReplaceAll = True SendKeys "%m" '**** SendKeys "%y" '**** SendKeys "%a" 'Th
One iteration will give whole words only and the next iteration gives a instances. It is late and I haven't figured out if it is possible to do whole word only consistently.
 Signature Greg Maxey/Word MVP See: http://gregmaxey.mvps.org/word_tips.htm For some helpful tips using Word.
> I like Helmut's approach - almost. > [quoted text clipped - 94 lines] >> Win XP, Office 2003 >> "red.sys" & Chr$(64) & "t-online.de" Greg Maxey - 14 Apr 2006 12:47 GMT I had failed to reset find and replace parameters. With that and then additional sendkeys, you can restrict the count to whole words only:
Sub test() Dim ss As String ' short string, the number of replacements Dim sl As String ' long string, the error message Dim l As Long ' just a loop variable Dim oDlg As Dialog ResetFRParameters ActiveDocument.Range(0, 0).Select Selection.ExtendMode = False Set oDlg = Dialogs(wdDialogEditReplace) On Error Resume Next oDlg.Find = "a" oDlg.Replace = "a" oDlg.ReplaceAll = True SendKeys "%m" SendKeys "%y" SendKeys "%a" SendKeys "{tab}" SendKeys "{tab}" SendKeys "{tab}" SendKeys "{enter}" oDlg.Display sl = Err.Description For l = 1 To Len(sl) If IsNumeric(Mid(sl, l, 1)) Then ss = ss & Mid(sl, l, 1) End If Next ResetFRParameters MsgBox " Found: " & ss & " times" End Sub Sub ResetFRParameters() With Selection.Find .ClearFormatting .Replacement.ClearFormatting .Text = "" .Replacement.Text = "" .Forward = True .Wrap = wdFindContinue .Format = False .MatchCase = False .MatchWholeWord = False .MatchWildcards = False .MatchSoundsLike = False .MatchAllWordForms = False .Execute End With End Sub
Helmut Weber - 14 Apr 2006 12:56 GMT Hi Ricardo,
my attempt was meant as a standalone macro, for counting the number of occurences of a single word or whatever only every now and then with varying options.
I'd use "range.find", if options had to be defined, and instr, replace etc. in other cases. Maybe "Ubound" of "split", too, depending on size and structure of the doc.
The strange thing about the error is, that it seems to be immanent, in a way. A search stops when no more occurences are to be found, and this constitutes the error...
Mere speculation, of course.
 Signature Greetings from Bavaria, Germany
Helmut Weber, MVP WordVBA
Win XP, Office 2003 "red.sys" & Chr$(64) & "t-online.de"
Greg Maxey - 14 Apr 2006 12:58 GMT Ricardo,
How about an input box to set the .Find value and simply using ^& as the replace variable:
Sub test() Dim ss As String ' short string, the number of replacements Dim sl As String ' long string, the error message Dim l As Long ' just a loop variable Dim oDlg As Dialog Dim oFind As String Dim oString As String ResetFRParameters ActiveDocument.Range(0, 0).Select Selection.ExtendMode = False oFind = InputBox("Type the word to find:") Set oDlg = Dialogs(wdDialogEditReplace) On Error Resume Next oDlg.Find = oFind oDlg.Replace = "^&" oString = oDlg.Find oDlg.ReplaceAll = True SendKeys "%m" SendKeys "%y" SendKeys "%a" SendKeys "{tab}" SendKeys "{tab}" SendKeys "{tab}" SendKeys "{enter}" oDlg.Display sl = Err.Description For l = 1 To Len(sl) If IsNumeric(Mid(sl, l, 1)) Then ss = ss & Mid(sl, l, 1) End If Next ResetFRParameters MsgBox oString & ": was found (" & ss & ") times" End Sub Sub ResetFRParameters() With Selection.Find .ClearFormatting .Replacement.ClearFormatting .Text = "" .Replacement.Text = "" .Forward = True .Wrap = wdFindContinue .Format = False .MatchCase = False .MatchWholeWord = False .MatchWildcards = False .MatchSoundsLike = False .MatchAllWordForms = False .Execute End With End Sub
Greg Maxey - 14 Apr 2006 12:52 GMT One thing I couldn't manage, was to put the find-string in the message, like:
Helmut, using Ricado's adaption we can set a string value equal to oDlg.Find and then:
Sub test() Dim ss As String ' short string, the number of replacements Dim sl As String ' long string, the error message Dim l As Long ' just a loop variable Dim oDlg As Dialog Dim oString As String ResetFRParameters ActiveDocument.Range(0, 0).Select Selection.ExtendMode = False Set oDlg = Dialogs(wdDialogEditReplace) On Error Resume Next oDlg.Find = "a" oDlg.Replace = "a" oString = oDlg.Find oDlg.ReplaceAll = True SendKeys "%m" SendKeys "%y" SendKeys "%a" SendKeys "{tab}" SendKeys "{tab}" SendKeys "{tab}" SendKeys "{enter}" oDlg.Display sl = Err.Description For l = 1 To Len(sl) If IsNumeric(Mid(sl, l, 1)) Then ss = ss & Mid(sl, l, 1) End If Next ResetFRParameters MsgBox oString & ": was found (" & ss & ") times" End Sub
Sub ResetFRParameters() With Selection.Find .ClearFormatting .Replacement.ClearFormatting .Text = "" .Replacement.Text = "" .Forward = True .Wrap = wdFindContinue .Format = False .MatchCase = False .MatchWholeWord = False .MatchWildcards = False .MatchSoundsLike = False .MatchAllWordForms = False .Execute End With End Sub
Helmut Weber - 14 Apr 2006 13:38 GMT Hi Greg,
hmm..., you've read my other posting in the meantime, I guess.
I thought about letting the user fill in what he was searching for. Ideally, the macro would set oDlg.replace to oDlg.find automatically and, of course, you know about sendkeys.
Thinking one step further, IMHO, with options we will arrive at range.find or range.replace anyway, and would have to replace the poorly documented dialog by a userform of our own.
By hindsight, it is all about that search always results in an error, and that the messagebox, Word presents after a search, is the error message.
 Signature Greetings from Bavaria, Germany
Helmut Weber, MVP WordVBA
Win XP, Office 2003 "red.sys" & Chr$(64) & "t-online.de"
Greg Maxey - 14 Apr 2006 14:46 GMT Of course. Interesting discovery about the error.
George Lee - 17 Apr 2006 14:46 GMT One of the posters has a point. The Search dialog keeps displaying and is an interface nuisance. Is there a way to keep the dialog from showing up?
> Hi Greg, > [quoted text clipped - 14 lines] > and that the messagebox, Word presents after a search, > is the error message. Helmut Weber - 17 Apr 2006 19:44 GMT Hi George,
if you need user interaction, then you need some kind of a a dialog.
If you don't need user interaction, then it is all about instr or replace or split or whatever without formatting, and range.find with or without formatting, as other posters have pointed out.
Maye be there was a sample with just "find" missing, like:
Sub Macro4() Dim rDcm As Range Dim l As Long Set rDcm = ActiveDocument.Range With rDcm.Find .Text = "brown" .Font.Name = "Times New Roman" .Format = True While .Execute l = l + 1 Wend End With MsgBox l End Sub
 Signature Greetings from Bavaria, Germany
Helmut Weber, MVP WordVBA
Win XP, Office 2003 "red.sys" & Chr$(64) & "t-online.de"
paulag1955 - 17 Apr 2006 21:31 GMT Here is a related question:
Is it then possible to take the answer (the number of occurrences), compare it to the number of pages in the document, then either display a message box showing the number of occurrences OR solicit input from the user, then add a line of text to the document?
> I know I've seen this posted before but... > [quoted text clipped - 3 lines] > interface (something like "This or that has been replaced 993 times"). How > can get hold of the text from that message? Jezebel - 17 Apr 2006 21:56 GMT Yes.
> Here is a related question: > [quoted text clipped - 14 lines] >> How >> can get hold of the text from that message?
|
|
|