extract count from find&replace in Word vba - vba

I have a macro which searches for a paragraph break ("^p") in a selection of text. I notice that, in the Advanced Find & Replace Screen, word tells you how many instances of the search item has been found. How do I extract this count?
I have recorded a VBA macro which does the find in a selection, but I don't know how to extract the number of occurrences from that selection. Does anyone know how to do this (would prefer to just extract it from the find&replace function as opposed to writing a for-loop)?
Selection.Find.ClearFormatting
With Selection.Find
.Text = "^p"
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindAsk
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
End With

You can't - that isn't exposed to the developer, unfortunately!
But you don't necessarily have to loop Word's Find. You can use other functionality which executes faster than the object model to count the number of instances of a string. For example loop Instr to count the number of instances:
Sub TestGetCountOfFoundInstances()
Dim rng As Word.Range
Dim searchTerm As String
Dim nrInstances As Long
Dim bFound As Boolean
searchTerm = Chr(13)
Set rng = Selection.Range
nrInstances = CountNrInstancesSearchTerm(rng, searchTerm)
Debug.Print "The term " & searchTerm & " was found " & nrInstances & _
" times."
bFound = rng.Find.Execute(findText:="^p", ReplaceWith:="^l", Replace:=wdReplaceAll)
End Sub
Function CountNrInstancesSearchTerm( _
rng As Word.Range, searchTerm As String) As Long
Dim counter As Long, loc As Long, startPos As Long
Dim t As String
t = rng.Text
startPos = 1
Do
loc = InStr(startPos, t, searchTerm)
If loc > 0 Then
counter = counter + 1
startPos = loc + 1
End If
Loop While loc > 0
CountNrInstancesSearchTerm = counter
End Function

Related

MS-Word(Mac) Type Case Macro - Fixing abbreviations with specific capitalized letters

I am trying to tweak/add to a type case macro I made and have been working on that I use in MS-Word (mac). I am trying to add to the macro to recognize specific abbreviations and convert them to a specific type case. For example, converting "ml" or "Ml" or "ML" to mL. Converting "gm" or "Gm" or "GM" to g.
I have attached my code below of what I have so far that fixes/ignores capitalizations, I just need help adding in these new rules. I am guessing I would have to create a bunch of specific If/Then statements, but I am not exactly sure.
Sub CaseFix()
'
' CaseFix Macro
'
'
Dim lclist As String
Dim wrd As Integer
Dim sTest As String
' list of lowercase words, surrounded by spaces
lclist = " of or the by your to this into at but with on compare compared is in for from a an and cm min minutes minute sec seconds mL gm g "
Selection.Range.Case = wdTitleWord
For wrd = 2 To Selection.Range.Words.Count
sTest = Trim(Selection.Range.Words(wrd))
sTest = " " & LCase(sTest) & " "
If InStr(lclist, sTest) Then
Selection.Range.Words(wrd).Case = wdLowerCase
End If
Next wrd
End Sub
For an existing document:
Sub CaseFix()
Application.ScreenUpdating = False
Dim FList As String, RList As String, j As Long
FList = "aaa,aba,aca,ada"
RList = "AAa,aBa,ACA,AdA"
With ActiveDocument.Range.Find
.ClearFormatting
.Replacement.ClearFormatting
.Format = False
.Forward = True
.MatchWholeWord = True
.MatchWildcards = False
'Process each word from the Find/Replace Lists
For j = 0 To UBound(Split(FList, ","))
.Text = UCase(Split(FList, ",")(j))
.Replacement.Text = Split(RList, ",")(j)
.MatchCase = False
.Execute Replace:=wdReplaceAll
.MatchCase = True
.Execute Replace:=wdReplaceAll
Next
End With
Application.ScreenUpdating = True
End Sub
Note that you must have the same number of comma-separated entries in the FList and RList.

Find, highlight and list count of instances of words found in document using VBA

I have a list of keywords that I need to search for in Word documents.
I made a script that searches the document and highlights all instances found, including matching all word forms (i.e. fix, fixed, fixing). After processing, a message box appears that is supposed to summarize the count of instances found for each word.
The problem is that although the highlighting routine allows for all word forms (.MatchAllWordForms = True), I'm missing something for the count, such that only exact matches are tallied.
Can you help me update this so that all words and word forms are both highlighted and summarized in the message box?
'
' Highlight Macro
Sub HighlightKeywords()
Dim range As range
Dim i As Long
Dim Keywords
' put list of terms to find here
Keywords = Array("wrong", "broke", "fix", "swap", "missing", "mistake", "revert", "oops", "backwards", "shatter", "drop")
For i = 0 To UBound(Keywords)
Set range = ActiveDocument.range
With range.Find
.Text = Keywords(i)
.Format = True
.MatchCase = True
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = True
Do While .Execute(Forward:=True) = True
range.HighlightColorIndex = wdYellow
Loop
End With
Next
ReDim numfound(0 To UBound(Keywords))
For Each wrd In ActiveDocument.Words
idx = 0
For Each var In Keywords
If Trim(wrd.Text) = Keywords(idx) Then
numfound(idx) = numfound(idx) + 1
End If
idx = idx + 1
Next var
Next wrd
idx = 0
For Each var In Keywords
strResults = strResults & Keywords(idx) & " : " & _
numfound(idx) & vbCr
idx = idx + 1
Next var
MsgBox strResults
End Sub
A message box has very limited output capacity. If you really want to go down that path, try:
Sub HighlightKeywords()
Application.ScreenUpdating = False
Dim i As Long, j As Long, Keywords, StrOut As String
' put list of terms to find here
Keywords = Array("wrong", "broke", "fix", "swap", "missing", "mistake", "revert", "oops", "backwards", "shatter", "drop")
For i = 0 To UBound(Keywords)
j = 0
With ActiveDocument.Range
With .Find
.Text = Keywords(i)
.Format = False
.MatchCase = True
.MatchAllWordForms = True
.MatchWildcards = False
.Forward = True
.Wrap = wdFindStop
.Execute
End With
Do While .Find.Found = True
j = j + 1
.Duplicate.HighlightColorIndex = wdYellow
.Collapse wdCollapseEnd
.Find.Execute
Loop
End With
StrOut = StrOut & vbCr & Keywords(i) & ": " & j
Next
Application.ScreenUpdating = True
MsgBox "Found the following:" & StrOut
End Sub

VBA macro filter in search highlight string

I am searching a long MS Word document for words that end in ly and highlighting them yellow.
However, certain words that end in ly are not adverbs (only, family) and I want to skip those.
How do I mod my code logic to do this:
If word=TargetList Then [If word=ExceptionList Then Skip ] Else [ highlight ]
Is a filter statement needed?
Sub FindAdverbs()
'
' FindAdverbs Macro
'
'
Dim range As range
Dim i As Long
Dim TargetList
TargetList = Array("ly") ' 'string to search for
ExceptionList = Array("family", "only") 'string of words to ignore
For i = 0 To UBound(TargetList)
Set range = ActiveDocument.range
With range.Find
.Text = TargetList(i)
.Format = True
.MatchCase = True
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
Do While .Execute(Forward:=True) = True
range.HighlightColorIndex = wdYellow
Loop
End With
Next
End Sub
Please try this code. Apart from what #Peh said about using reserved words for naming variables, I have avoided the use of variants. MS Word is about text and text is contained in strings. To use them is both easier and more efficient when manipulating texts.
Sub FindAdverbs()
' 03 Jun 2017
Dim Targets() As String
Dim Exceptions As String
Dim Rng As Range
Dim LastFound As Long, RngEnd As Long
Dim n As Long
Dim i As Long
Targets = Split("ly,lo", ",") 'string to search for
Exceptions = "family,only" 'string of words to ignore
For i = 0 To UBound(Targets)
Set Rng = ActiveDocument.Content
With Rng.Find
.Text = "*" & Targets(i)
.MatchCase = True
.MatchWholeWord = True
.MatchWildcards = True
.Format = False
.Forward = True
.MatchSoundsLike = False
.MatchAllWordForms = False
Do
.Execute
With Rng
If (.End <= LastFound) Then Exit Do
LastFound = .End
RngEnd = .End
.Collapse wdCollapseEnd
.MoveStart wdWord, -1
n = .MoveEndUntil(".,;:!?" & Chr(9) & Chr(10) & Chr(11) & Chr(12) & Chr(13) & Chr(32))
If (InStr(1, Exceptions, Trim(.Text), vbTextCompare) = 0) And (n = 1) Then
.HighlightColorIndex = wdYellow
End If
.SetRange RngEnd, RngEnd
End With
Loop While .Found
End With
Next i
End Sub
As another change I made which is worthy of your attention is in the line .Text = "*" & Targets(i). This will ensure that words containing "ly" in a position other than at the end will not be turned up by the search.

Expanding a range in VBA

I am in the process of putting together a Word macro (below) that parses a table of acronyms in one Word document and highlights every occurrence of these acronyms in another Word document. This appears to be functional.
However, I would like to also have the macro differentiate acronyms that are in parentheses from those that are not. For example,
The soldier is considered Away Without Leave (AWOL). AWOL personnel are subject to arrest.
It seems as though the range "oRange" that defines the found acronym could be evaluated, if it is first expanded in the Do-While loop using this code:
oRange.SetRange Start:=oRange.Start - 1, End:=oRange.End + 1
However, none of my attempts to code a solution seem to work (they put the macro into an infinite loop or result in error messages). I'm fairly new to VBA programming and am obviously missing something regarding how the loops are operating.
My question is: is there a way to duplicate the range "oRange" for subsequent manipulation or is there some other method that I should be using?
Thanks for any assistance you can provide!
Sub HighlightAcronyms()
Dim wdDoc As Object
Dim wdFileName As Variant
Dim TableNo As Integer 'table number in Word
Dim oRow As Row
Dim oCell As Cell
Dim sCellText As String
Dim oDoc_Source As Document
Dim strListSep As String
Dim oRange As Range
Dim n As Long
Dim sCellExpanded As String
'Application.ScreenUpdating = False
strListSep = Application.International(wdListSeparator)
'*** Select acronym file and check that it contains one table
wdFileName = WordApplicationGetOpenFileName("*.docx", True, True)
If wdFileName = False Then Exit Sub '(user cancelled import file browser)
Set wdDoc = GetObject(wdFileName) 'open Word file
With wdDoc
TableNo = wdDoc.Tables.Count
If TableNo = 0 Then
MsgBox "The file """ & wdFileName & """ contains no tables.", _
vbExclamation, "Import Word Table"
ElseIf TableNo > 1 Then
MsgBox "The file """ & wdFileName & """ contains multiple tables.", _
vbExclamation, "Import Word Table"
End If
End With
'*** steps through acronym column
wdDoc.Tables(1).Cell(1, 1).Select
Selection.SelectColumn
For Each oCell In Selection.Cells
' Remove table cell markers from the text.
sCellText = Left$(oCell.Range, Len(oCell.Range) - 2)
sCellExpanded = "(" & sCellText & ")"
n = 1
'need to find foolproof method to select document for highlighting
Documents(2).Activate
Set oDoc_Source = ActiveDocument
With oDoc_Source
Set oRange = .Range
With oRange.Find
.Text = sCellText
.Forward = True
.Wrap = wdFindStop
.Format = False
.MatchCase = True
.MatchWildcards = False
Do While .Execute
If n = 1 Then
oRange.HighlightColorIndex = wdGreen
Else
oRange.HighlightColorIndex = wdYellow
End If
'trying to add code here to expand oRange and compare it to sCellExpanded
n = n + 1
Loop
End With
End With
Next oCell
Set wdDoc = Nothing
End Sub
Try This
Define two ranges instead of merging the oRange.
See this sample code (TRIED AND TESTED)
Sub Sample()
Dim strSearch As String, sCellExpanded As String
Dim oRange As Range, newRange As Range
strSearch = "AWOL"
sCellExpanded = "(" & strSearch & ")"
Set oRange = ActiveDocument.Range
With oRange.Find
.ClearFormatting
.Text = strSearch
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindStop
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
Do While .Execute
If n = 1 Then
oRange.HighlightColorIndex = wdGreen
Else
oRange.HighlightColorIndex = wdYellow
End If
'~~> To check if the found word is not the 1st word.
If oRange.Start <> 0 Then
Set newRange = ActiveDocument.Range(Start:=oRange.Start - 1, End:=oRange.End + 1)
If newRange.Text = sCellExpanded Then
'
'~~> Your code here
'
newRange.Underline = wdUnderlineDouble
End If
End If
n = n + 1
Loop
End With
End Sub
SNAPSHOT
Unable to upload image at the moment. imgur server is down at the moment.
You may see this link
http://wikisend.com/download/141816/untitled.png

How to set some sort of array for VBA find/replace scripts

UPDATED SCRIPT I'M USING THAT CAUSES LOCKUP...I tried replacing the (Replace:=wdReplaceOne) with (Replace:=wdReplaceAll), but still no such luck:
Option Explicit
'Dim strMacroName As String
Dim spellingcorrectionsrep As Long
Public Sub SpellingReview()
Dim oShell, MyDocuments
'Declaring the MyDocs filepath:
Set oShell = CreateObject("Wscript.Shell")
MyDocuments = oShell.SpecialFolders("MyDocuments")
Set oShell = Nothing
' Set values for variables of the actual word to find/replace
spellingsuggestionsrep = 0
spellingcorrectionsrep = 0
' Replacements
SpellingCorrections "dog", "dog (will be changed to cat)", False, True
' END SEARCHING DOCUMENT AND DISPLAY MESSAGE
MsgBox spellingcorrectionsrep
'strMacroName = "Spelling Review"
'Call LogMacroUsage(strMacroName)
End Sub
Sub SpellingCorrections(sInput As String, sReplace As String, MC As Boolean, MW As Boolean)
' Set Selection Search Criteria
Selection.HomeKey Unit:=wdStory
With Selection
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Replacement.Highlight = True
.Text = sInput
.Replacement.Text = sReplace
.Forward = True
.Wrap = wdFindStop
.Format = True
.MatchWildcards = False
.MatchCase = MC
.MatchWholeWord = MW
End With
Do While .Find.Execute = True
If .Find.Forward = True Then
.Collapse Direction:=wdCollapseStart
Else
.Collapse Direction:=wdCollapseEnd
End If
If .Find.Execute(Replace:=wdReplaceOne) = True Then
spellingcorrectionsrep = spellingcorrectionsrep + 1
End If
If .Find.Forward = True Then
.Collapse Direction:=wdCollapseStart
Else
.Collapse Direction:=wdCollapseEnd
End If
Loop
End With
End Sub
Why not use it as a common procedure?
Option Explicit
Dim wordRep As Long
Public Sub SpellingReview()
Dim oShell, MyDocuments
wordRep = 0
SpellingCorrections "Dog", "Dog (will be changed to DOG)", False, True
MsgBox wordRep
End Sub
Sub SpellingCorrections(sInput As String, sReplace As String, MC As Boolean, MW As Boolean)
With ActiveDocument.Content.Find
Do While .Execute(FindText:=sInput, Forward:=True, Format:=True, _
MatchWholeWord:=MW, MatchCase:=MC) = True
wordRep = wordRep + 1
Loop
End With
With Selection.Find
.ClearFormatting
.Replacement.ClearFormatting
.Replacement.Highlight = True
.Text = sInput
.Replacement.Text = sReplace
.Forward = True
.Wrap = wdFindContinue
.Format = True
.MatchCase = MC
.MatchWholeWord = MW
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
.Execute Replace:=wdReplaceAll
End With
End Sub
Creating an Array to store the information isn't too hard
Dim Dict() As Variant
' Integer ReplacementCount, String FindText, Boolean MatchCase, Boolean MatchWholeWord, String ReplaceText
Dict = Array( _
Array(0, "Word", True, True, "word"), _
Array(0, "Word1", True, True, "word1"), _
Array(0, "Word2", True, True, "word2"), _
Array(0, "Word3", True, True, "word3") _
)
Using this you could loop through each item and store the replacement counter in the same array.
For Index = LBound(Dict) To UBound(Dict)
Do While ReplaceStuffFunction(WithArguments) = True
Dict(Index)(0) = Dict(Index)(0) + 1
Loop
Next Index
When I tried your first example code it didn't seem to replace ALL instances, just one per run of the sub so either I did it wrong or something not right (or its not meant to do it)
'In this example, I used two arrays to shorten formal hospital names
'Define two arrays (I used FindWordArray and ReplacewordArray)
'The position of the word (by comma) in each arrays correspond to each other
Dim n as long
Dim FindWordArray, ReplaceWordArray As String 'Change information pertinent to your needs
Dim FWA() As String 'Find words array created by split function
Dim RWA() As String 'Replace array created by split function
Dim HospitalName As String 'This is the string to find and replace
FindWordArray = ("Hospital,Center,Regional,Community,University,Medical") 'change data here separate keep the quotes and separate by commas
FWA = Split(FindWordArray, ",")
ReplaceWordArray = ("Hosp,Cntr,Reg,Com,Uni,Med") 'change data here keep the quotes but separate by commas
RWA = Split(ReplaceWordArray, ",")
'Loop through each of the arrays
For n = LBound(FWA) To UBound(FWA)
HospitalName = Replace(HospitalName, FWA(n), RWA(n))
Next n