I have a word document with tables containing hyperlinks to other word documents, see image below. The word documents are catogorized into groups, i.e 1 table for each group.
My problem is that sometimes people messes around with the formatting, such as adding a newline or removing a newline between the tables(so it becomes 1,2,3,4 newlines instead of 2 as my code requires) or change the order to not be alphabetic(rare and I can live with that).
So finally to my problem, In this case I created a new document PL_xxxx and the table PL does not exist, so it should insert a new table, but with SINGLE newline between tables this get inserted inside another table instead of in between tables.
' Now move up two lines, beyond the table end
Selection.MoveUp Unit:=wdLine, Count:=2
So how can I either ensure that it is always consistence newlines between tables? Is there a way to remove all newlines between tables and then recreate them, and then do the table insert? Or can I somehow loop through all tables in documents? Or is there some other way to make sure that mistakes not like this happens?
So here is my main code:
'here we alter the docout tables
If Not searchAll(dokType) Then
Call addList(dokType, Settings.documentTypeFile)
docNumber = "01"
Else
Below is my code that seach if PL exist, which will return false in this case:
' Moves cursor to the place the given string is found, or replace it
Function searchAll(searchText As String, Optional replaceText As String = "GGG") As Boolean
'default false
searchAll = False
If Not replaceText = "GGG" Then
With ActiveDocument.Range.Find
.Text = searchText
.forward = True
.Wrap = wdFindContinue
.Format = True
.MatchCase = True
.MatchWholeWord = True
.Replacement.Text = replaceText
If .Execute(Replace:=wdReplaceAll) Then
searchAll = True
End If
End With
'just searching
Else
With Selection.Find
.Text = searchText
.forward = True
.Wrap = wdFindContinue
.Format = True
.MatchCase = True
.MatchWholeWord = True
If .Execute Then
searchAll = True
End If
End With
End If
End Function
Here is the code that actually figures out where to place the table and add its, and here is the problem(rewrite to loop through tables instead or modify the moveup function)
Sub addList(tableKey As String, filenameTypes As String)
Dim dict As Object
Dim addAtEnd As Boolean
Dim keyArray As Variant
Dim startSearching As Boolean
Dim element As Variant
'Dictionary with all types
Set dict = getTypes(filenameTypes)
With dict
addAtEnd = False
'extract keys into variant array
keyArray = .keys
startSearching = False
For Each element In keyArray
'looping untill we find the element we want to add
If element = tableKey Then
startSearching = True
End If
'Finding the next table after were we want to insert
If startSearching Then
If searchAll(CStr(element)) Then
addAtEnd = False
Exit For
Else
addAtEnd = True
End If
End If
Next
If addAtEnd Then
Selection.EndKey Unit:=wdStory
Else
Call HelpFunctions.moveCursorUp(CStr(element))
End If
Call addTable("UT", tableKey, .item(tableKey), Settings.docUtPath)
End With
Set dict = Nothing
End Sub
And finally the move up function which then obviously moves up to much and inside the next table.
'move cursor up
Function moveCursorUp(searchText As String)
If Not searchAll(searchText) Then
MsgBox "Failed to move cursor"
Else
'Selection.Tables(1).Select
If Selection.Information(wdWithInTable) Then
Selection.Tables(1).Range.Select
Selection.Collapse 1
' Now move up two lines, beyond the table end
Selection.MoveUp Unit:=wdLine, Count:=2
End If
'Selection.Collapse WdCollapseDirection.wdCollapseStart
End If
End Function
And here is the addtable code which basically has an empty tabley stored in a seperate file.
Function addTable(typeOfTable As String, category As String, description As String, templateFolder As String)
'Insert out table
If UCase(typeOfTable) = "UT" Then
Selection.InsertFile FileName:=templateFolder + "\Doklistut.doc", Range:="", _
ConfirmConversions:=False, link:=False, Attachment:=False
'insert inn table
ElseIf UCase(typeOfTable) = "INN" Then
Selection.InsertFile FileName:=templateFolder + "\Doklistinn.doc", Range:="", _
ConfirmConversions:=False, link:=False, Attachment:=False
Else
MsgBox "wrong argument given: either inn or ut is allowed"
Exit Function
End If
'Replace the DT with the category
If Not searchAll("DT", category) Then
MsgBox "Failed to replace category in table"
End If
'Replace the Dokumenttype with the category
If Not searchAll("Dokumenttype", description) Then
MsgBox "Failed to replace document type in table"
End If
End Function
So thanks to all the input I have now revised the code totally and it is now working as desired, It can probably be improved, especially the selection method.
Sub addList(tableKey As String, tableDescription As String)
Selection.EndKey Unit:=wdStory
Call addTable(tableKey, tableDescription)
Call SortTables
End Sub
Sub Deleemptylines()
Selection.Find.ClearFormatting
Selection.Find.Replacement.ClearFormatting
With Selection.Find
.Text = "^p"
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindContinue
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchByte = False
.MatchAllWordForms = False
.MatchSoundsLike = False
.MatchWildcards = False
.MatchFuzzy = False
End With
Selection.Find.Execute Replace:=wdReplaceAll
End Sub
Sub SortTables()
Dim i As Long
Dim iMin As Long
Dim iMax As Long
Dim blnSwapped As Boolean
Call Deleemptylines
iMin = 1
iMax = ActiveDocument.Tables.Count - 1
Do
blnSwapped = False
For i = iMin To iMax
If ActiveDocument.Tables(i).Cell(1, 1).Range.Text > ActiveDocument.Tables(i + 1).Cell(1, 1).Range.Text Then
ActiveDocument.Tables(i).Range.Cut
ActiveDocument.Tables(i).Select
Selection.Collapse WdCollapseDirection.wdCollapseEnd
Selection.Paragraphs.Add
Selection.Paragraphs.Add
Selection.MoveDown Unit:=wdLine, Count:=1
Selection.MoveUp Unit:=wdLine, Count:=1
Selection.Paste
blnSwapped = True
End If
Next i
iMax = iMax - 1
Loop Until Not blnSwapped
Call Deleemptylines
End Sub
Function addTable(category As String, description As String)
'Insert out table
Selection.InsertFile FileName:=Settings.docUtPath + "\Doklistut.doc", Range:="", _
ConfirmConversions:=False, link:=False, Attachment:=False
'Replace the DT with the category
If Not searchAll("DT", category) Then
MsgBox "Failed to replace category in table"
End If
'Replace the Dokumenttype with the category
If Not searchAll("Dokumenttype", description) Then
MsgBox "Failed to replace document type in table"
End If
End Function
Related
I would like to fix the following code to make it find each table in the document where it has the pattern ARC or MEC words followed by the wildcard digits [1-4][1-9]{2} without any leading/trailing characters, digits, spaces, etc.
The chosen table should have a total of 11 rows.
If possible, I need another version of the code to search for the pattern in the table first cell .Cell(1,1) while making sure the table has a total of 11 rows.
Sub FindTables()
Dim wdDoc As Word.Document, t As Long
Set wdDoc = ThisDocument
With wdDoc
For t = 1 To .Tables.Count
With .Tables(t).Range.Find
.ClearFormatting
.Format = FALSE
.Text = "(ARC)|(MEC)[1-4][1-9]{2}"
.Forward = TRUE
.Wrap = wdFindStop
.MatchCase = TRUE
.MatchWildcards = TRUE
.Execute
If .Found = TRUE Then
' some operations on the table
wdDoc.Tables(t).AutoFitBehavior (wdAutoFitWindow)
wdDoc.Tables(t).Range.Collapse wdCollapseEnd
End If
End With
Next
End With
End Sub
For example:
Sub Demo()
Application.ScreenUpdating = False
With ActiveDocument.Range
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Format = False
.Forward = True
.Wrap = wdFindStop
.MatchWildcards = True
.Text = "<[ACEMR]{3}[1-4][1-9]{2}>"
.Replacement.Text = ""
End With
Do While .Find.Execute = True
If .Information(wdWithInTable) = True Then
If .Tables(1).Rows.Count = 11 Then
'If .Cells(1).RowIndex = 1 And .Cells(1).ColumnIndex = 1 Then
If Split(.Cells(1).Range.Text, vbCr)(0) = .Text Then
Select Case Left(.Text, 3)
Case "ARC", "MEC": .Tables(1).AutoFitBehavior (wdAutoFitWindow)
End Select
End If
'End If
End If
.Start = .Tables(1).Range.End
End If
.Collapse wdCollapseEnd
Loop
End With
Application.ScreenUpdating = True
End Sub
To process only those tables where the found content is in the first cell, delete the tick marks from the two comment-out lines.
Pattern:
"(ARC[1-4][1-9]{2})|(MEC[1-4][1-9]{2})"
Tested successfully with Microsoft VbScript Regular Expressions 5.5. (set this Reference on VBE).
Code sample - adapt it to suit your needs (working with tables - I didn't reproduce your scenario):
Function fnFindPatterns()
Dim objRegExp As RegExp
Dim ObjMatch As Match
Dim colMatches As MatchCollection
Dim strText As String
Dim strResult As String
Set objRegExp = New RegExp
objRegExp.Pattern = "(ARC[1-4][1-9]{2})|(MEC[1-4][1-9]{2})"
objRegExp.IgnoreCase = True
objRegExp.Global = True
Selection.WholeStory
strText = Selection.Text
If objRegExp.Test(strText) = True Then 'we have something there...
Set colMatches = objRegExp.Execute(strText)
For Each ObjMatch In colMatches 'Iterate on the collection
strResult = strResult & ObjMatch.Value & vbCrLf
Next
Else
End If
MsgBox strResult
End Function
Edited 2022 07 11:
I realized that the "|" (OR) do not work in MSWord . It doesn't exist on the limited "Regular Expressions" set of tools within MsWord, compared to VbScript.RegExp. Wich, in turn, is also limited set of tools, if compared with other (powerfull) programming languages. But with some coding we "simulate" this OR, using "Choose", testing each partial set of patterns that way:
Sub FindTables()
Dim wdDoc As Word.Document, t As Long, intChoose As Integer
Set wdDoc = ThisDocument
With wdDoc
For intChoose = 1 To 2
For t = 1 To .Tables.Count
With .Tables(t).Range.Find
.ClearFormatting
.Format = False
.Text = VBA.Choose(intChoose, "<[ARC]{3}[1-4][1-9]{2}>", "<(MEC)[1-4][1-9]{2}>")
.Forward = True
.Wrap = wdFindStop
.MatchCase = True
.MatchWildcards = True
.Execute
If .Found = True Then
' some operations on the table
wdDoc.Tables(t).AutoFitBehavior (wdAutoFitWindow)
wdDoc.Tables(t).Range.Collapse wdCollapseEnd
End If
End With
Next
Next
End With
End Sub
To test this code I mounted a Word Doc with 7 tables (varying dimensions from 1 x 11 to 1 x 13). To ensure the correct dimension of each table insert the suggestion posted in Macropod's code.
Acronym Search
When findRng.Find successfully discovers the search text within a field result (such as Table of Contents) the next .Execute begins at the start of the TOC rather than at the start position that had been set further down the document from the previous findRng.Find. This can be visually shown by choosing findRng.select. Per the findRng's Start and End properties, the selection should not include the start of the TOC, but it does AND this appears to be what the .Find method is also using because it becomes an Apple Corporate Headquarters address; i.e., One Infinite Loop. ;)
You can Watch the values of findRng.Start and .End which are as expected up until the .Execute statement near the bottom of the subroutine.
Unless anyone can fix the range reset issue I'd be happy just finding a way to quickly determine the .End location of the field that triggers wdInFieldResult yielding True and moving on with life.
Sub findAcronyms()
Dim findRng As Range, tempRng As Range
Dim oFld As Field
Dim findStr As String, acroStr As String
Dim acroTbl As Table
'################# test code
Dim testMode As Boolean
Dim testIdx As Long, testSize As Long, i As Long
testMode = True
testIdx = 0
testSize = 25
If testMode Then
ThisDocument.ShowRevisions = True
ThisDocument.TrackRevisions = True
End If
Quiet (Not testMode)
'#################
'set acroTbl to ThisDocument's Acronym table
Set findRng = ThisDocument.Content
findStr = "ACRONYMS"
With findRng.Find
.ClearFormatting
.Style = WdBuiltinStyle.wdStyleHeading1
.Text = findStr
.Forward = False
.Wrap = wdFindStop
.Format = False
.Execute
If Not .Found Then
MsgBox findStr & ": not found!", vbExclamation
Stop
Debug.Print "Debug the issue..."
Else
findRng.MoveStart wdTable
findRng.Expand wdTable
Set acroTbl = findRng.Tables(1)
End If
End With
'find occurrences of "(" and if closing parens "(" is within 7 characters then add to end of Acronym table
Set findRng = ThisDocument.Content
findStr = "("
With findRng.Find
.ClearFormatting
.Text = findStr
.Forward = True
.Wrap = wdFindStop
.Format = False
.Execute
Do While .Found 'until Find finds other than itself or EOD
'################# test code
If testMode Then
findRng.Select
Debug.Print findRng.Start
testIdx = testIdx + 1
If testIdx > testSize Then
Stop 'and Debug if necessary
Exit Sub
End If
End If
'################
i = findRng.MoveEndUntil(")", 7)
If i > 2 And Not findRng.Text Like Left(findStr & "#######", _
Len(findRng.Text)) Then
'check for pre-existence of acronym before adding to table
Set tempRng = ThisDocument.Range(acroTbl.Columns(1).Cells(2).Range.Start, _
acroTbl.Columns(1).Cells(acroTbl.Columns(1).Cells.Count).Range.End)
tempRng.Find.ClearFormatting
With tempRng.Find
.Text = Mid(findRng.Text, 2, i)
.Forward = True
.Wrap = wdFindStop
.Format = False
.MatchCase = False
.MatchWholeWord = True
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
.Execute
If Not .Found Then 'proceed with adding new acronym to table
With acroTbl.Rows
.Add
With .Last
.Cells(1).Range.Text = Mid(findRng.Text, 2, i)
i = findRng.Start
findRng.Collapse wdCollapseStart
findRng.MoveStart wdCharacter, -1
findRng.MoveStart wdWord, _
-.Cells(1).Range.Characters.Count
.Cells(2).Range.Text = Trim(findRng.Text)
findRng.Start = i + 1
Debug.Print .Cells(1).Range.Text, .Cells(2).Range.Text
End With
End With
End If
End With
Else: findRng.MoveStart wdWord 'skip over 2 letter acronyms
End If
If findRng.Information(wdInFieldResult) Then
findRng.MoveStart wdParagraph 'in lieu of a better solution I need to determine how to get out of the field result
ElseIf findRng.Information(wdWithInTable) Then
If findRng.InRange(findRng.Tables(1).Range.Cells(findRng.Tables(1).Range.Cells.Count).Range) Then 'test if in last cell
findRng.Expand wdTable
findRng.Collapse wdCollapseEnd
Else
findRng.MoveStart wdCell
End If
Else
findRng.MoveStart wdWord
End If
'################# test code
If testMode Then findRng.Select
'################
findRng.Collapse wdCollapseEnd
findRng.End = ThisDocument.Content.End
.Execute
Loop
End With
Stop
End Sub
Avoiding the broken behavior of Field.Result actually simplified the routine. Instead, employing Range.MoveStartUntil yielded more straightforward processing.
The findAcronyms routine searches thru ThisDocument.Content for each successive occurrence of open parens "(" until the end of document is reached. Upon finding an open parens, several filtering tests are run to eliminate undesirable results such as numeric strings and excessive acronym length (limited to 7 characters). If successful, the acronym is compared to the existing Acronym table for pre-existence before being appended with Track Changes enabled. Plural forms of acronyms (those with last character = "s") are reduced to singular form to again eliminate redundancies.
Finally, the newly appended acronyms are scrolled onto the screen and the User is prompted if they wish to accept and sort the table as is. This is followed by another prompt to perform a reverse check employing the checkAcronymUse routine. This Subr verifies whether each acronym in the table actually appears in the document. Useful when tailoring a document from an existing template with pre-populated Acronym table.
Option Explicit
Sub findAcronyms()
Dim findRng As Range, tempRng As Range
Dim findStr As String, acroStr As String
Dim acroTbl As Table
Dim sBool As Boolean
'################# test code
Dim testMode As Boolean
Dim testIdx As Long, testSize As Long, i As Long, j As Long
testMode = False
testIdx = 0
testSize = 100
Quiet (Not testMode)
'#################
'update all field codes and scroll to first occurrence of error
i = ThisDocument.Content.Fields.Update
If i > 0 Then
ThisDocument.ActiveWindow.ScrollIntoView ThisDocument.Range(i)
Stop 'and Debug as req'd
Exit Sub
End If
'set acroTbl to ThisDocument's Acronym table
Set findRng = ThisDocument.Content
findStr = "ACRONYMS"
With findRng.Find
.ClearFormatting
.Style = WdBuiltinStyle.wdStyleHeading1
.Text = findStr
.MatchWholeWord = False
.Forward = False
.Wrap = wdFindStop
.Format = False
.Execute
If Not .Found Then
MsgBox findStr & ": not found!", vbExclamation
Debug.Print "Debug the issue..."
Stop
Else
findRng.MoveStart wdTable
findRng.Expand wdTable
Set acroTbl = findRng.Tables(1)
End If
End With
' Main Loop: find occurrences of "(" and if closing parens ")" is within 7 characters then add to end of Acronym table
Set findRng = ThisDocument.Content
findStr = "("
With findRng
While .MoveStartUntil(findStr) > 0
sBool = False
'################# test code
If testMode Then
.Select
Debug.Print .Start
testIdx = testIdx + 1
If testIdx > testSize Then GoTo Finish
End If
'################
Set tempRng = .Duplicate
tempRng.End = .Start
i = tempRng.MoveEndUntil(")", 7) 'returns # of chars moved plus 1
If i > 3 Then 'filter out occurrences of single char parens; (?)
acroStr = Mid(tempRng.Text, 2, i)
If Right(acroStr, 1) = "s" Then
sBool = True
acroStr = Left(acroStr, Len(acroStr) - 1) 'exclude redundant plural form of acronym
End If
If Not acronymExists(acroTbl, acroStr) Then
addAcronym acroTbl, findRng.Duplicate, acroStr
If sBool Then 'remove plural "s" from acronym definition
With acroTbl.Rows.Last.Cells(2).Range
j = InStrRev(.Text, "s")
If j = Len(.Text) - 2 Then 'all cells contain two hidden characters after the end of text
ThisDocument.TrackRevisions = True
.Text = Mid(.Text, 1, j - 1)
ThisDocument.TrackRevisions = False
End If
End With
End If
End If
.MoveStart wdCharacter, i
Else: .MoveStart wdCharacter, 2
End If
Wend
End With
Finish:
ThisDocument.ActiveWindow.ScrollIntoView acroTbl.Range, False
If MsgBox("Accept and Sort Acronym table edits?", 65572, "Accept?") = 6 Then
With acroTbl
.Sort ExcludeHeader:=True, FieldNumber:="Column 1", SortFieldType:=wdSortFieldAlphanumeric, SortOrder:=wdSortOrderAscending, CaseSensitive:=True, LanguageID:=wdEnglishUS
.Range.Revisions.AcceptAll
End With
End If
If MsgBox("Verify Acronym table?", 65572, "Verify?") = 6 Then checkAcronymUse
Quiet (False)
End Sub
Sub checkAcronymUse()
Dim Rng As Range, findRng As Range
Dim srcDoc As Document
Dim myTblStyl As Style
Dim srcTbl As Table, tgtTbl As Table
Dim myRow As row
Dim r As Long
Dim findStr As String, srcAddr As String, srcDocName As String
Dim findBool As Boolean
'################# test code
Dim testMode As Boolean
Dim testSize As Long
testMode = False
testSize = 20
Quiet (Not testMode)
'#################
'set srcTbl to ThisDocument's Acronym table
Set Rng = ThisDocument.Content
findStr = "ACRONYMS"
With Rng.Find
.ClearFormatting
.Style = WdBuiltinStyle.wdStyleHeading1
.Text = findStr
.Forward = False
.Wrap = wdFindStop
.Format = False
.Execute
If Not .Found Then
MsgBox findStr & ": not found!", vbExclamation
Debug.Print "Debug the issue..."
Stop
Else
Rng.MoveStart wdTable
Rng.Expand wdTable
Set tgtTbl = Rng.Tables(1)
End If
End With
ThisDocument.ShowRevisions = True
ThisDocument.TrackRevisions = True
For Each myRow In tgtTbl.Rows
With myRow
If Not .HeadingFormat Then 'ignore column headings
findStr = Left(.Cells(1).Range.Text, .Cells(1).Range.Characters.Count - 1)
If Len(findStr) < 3 Then findStr = Left(.Cells(2).Range.Text, .Cells(2).Range.Characters.Count - 1)
Set findRng = ThisDocument.Content
findBool = False 'true if Find is outside of tgtTbl
With findRng.Find
.ClearFormatting
.MatchCase = True
.MatchWholeWord = False
.Text = findStr
.Forward = True
.Wrap = wdFindStop
.Format = False
.Execute
Do While .Found 'until Find finds other than itself or EOD
If findRng.InRange(tgtTbl.Range) Then
findRng.Expand wdTable
Else
findBool = True
Exit Do
End If
findRng.Collapse wdCollapseEnd
findRng.End = ThisDocument.Content.End
.Execute
Loop
End With
'################# test code
If testMode And .Index > testSize Then Exit For
'################
If Not findBool Then .Delete 'acronym not used; delete from table
End If
End With
Next myRow
'#################
If testMode Then Stop
'################
tgtTbl.Select
ThisDocument.TrackRevisions = False
Quiet (False)
End Sub
Function acronymExists(acroTbl As Table, str As String) As Boolean 'check for pre-existence of acronym to avoid duplication in acronym table
Dim tempRng As Range
If str Like Left("#######", Len(str)) Then 'filter out numerical strings
acronymExists = True
Else
Set tempRng = ThisDocument.Range(acroTbl.Columns(1).Cells(2).Range.Start, acroTbl.Columns(1).Cells(acroTbl.Columns(1).Cells.Count).Range.End)
tempRng.Find.ClearFormatting
With tempRng.Find
.Text = str
.Forward = True
.Wrap = wdFindStop
.Format = False
.MatchCase = False
.MatchWholeWord = True
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
.Execute
acronymExists = .Found
End With
End If
End Function
Sub addAcronym(acroTbl As Table, Rng As Range, str As String)
Dim ctr As Integer
ctr = Len(str)
ThisDocument.ShowRevisions = True
ThisDocument.TrackRevisions = True
With acroTbl.Rows
.Add
With .Last
.Cells(1).Range.Text = str
Rng.Collapse wdCollapseStart
'check words at, before, and just after ctr locations for simple correlation match to str
If Left(Rng.Previous(wdWord, ctr), 1) = Left(str, 1) Then
Rng.MoveStart wdWord, -ctr
ElseIf Left(Rng.Previous(wdWord, ctr + 1), 1) = Left(str, 1) Then
Rng.MoveStart wdWord, -ctr - 1
ElseIf Left(Rng.Previous(wdWord, ctr - 1), 1) = Left(str, 1) Then
Rng.MoveStart wdWord, -ctr + 1
Else: Rng.MoveStart wdWord, -ctr 'default, grab preceding words matching length of str
End If
.Cells(2).Range.Text = Trim(Rng.Text)
End With
End With
ThisDocument.TrackRevisions = False
End Sub
Sub Quiet(Optional bool As Boolean = True)
bool = Not bool
With Application
.ScreenUpdating = bool
.DisplayStatusBar = bool
End With
End Sub
I found this code online to search and highlight multiple words. It takes roughly about 10 min to run it on a 15 page document. I was wondering if it could be made to run any faster.
Sub HighlightMultipleWords()
Dim Word As Range
Dim WordCollection(2) As String
Dim Words As Variant
'Define list.
'If you add or delete, change value above in Dim statement.
WordCollection(0) = "word1"
WordCollection(1) = "word2"
WordCollection(2) = "word3"
'Set highlight color.
Options.DefaultHighlightColorIndex = wdYellow
'Clear existing formatting and settings in Find feature.
Selection.Find.ClearFormatting
Selection.Find.Replacement.ClearFormatting
'Set highlight to replace setting.
Selection.Find.Replacement.Highlight = True
'Cycle through document and find words in collection.
'Highlight words when found.
For Each Word In ActiveDocument.Words
For Each Words In WordCollection
With Selection.Find
.Text = Words
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindContinue
.Format = True
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
End With
Selection.Find.Execute Replace:=wdReplaceAll
Next
Next
End Sub
The comments are all correct here, you only need to run the find and replace once per item in your list, you are running it multiple times by the amount of words in the document.
Option Explicit
Sub HighlightMultipleWords()
Dim AryWords(2) As String
Dim VntStore As Variant
'Define list.
'If you add or delete, change value above in Dim statement.
AryWords(0) = "word1"
AryWords(1) = "word2"
AryWords(2) = "word3"
'Set highlight color.
Options.DefaultHighlightColorIndex = wdYellow
With Selection.Find
'Clear existing formatting and settings in Find feature.
.ClearFormatting
.Replacement.ClearFormatting
'Set highlight to replace setting.
Selection.Find.Replacement.Highlight = True
'Process the array
For Each VntStore In AryWords
.Execute FindText:=VntStore, _
MatchCase:=False, _
MatchWholeWord:=False, _
MatchWildcards:=False, _
MatchSoundsLike:=False, _
MatchAllWordForms:=False, _
Forward:=True, _
Wrap:=wdFindContinue, _
Format:=True, _
Replace:=wdReplaceAll
Next
End With
End Sub
I have several bookmarks in several Word Documents that need spaces added before and after all Bookmarks where a single space does not currently exist on either or both sides. I only want to be able to parse the current file.
I have tried several ways at doing this, several of which create infinate loops.
Using the following code, I have a level of success, however it creates an infinate loop in the process. I have tried looking through the Bookmark object, selecting each in turn and adding a space before and after, which causes spaces to be put within the bookmark or it ignores where the space should go and puts it after.
I have a macro that I run on the document that reveals the bookmarks and places it between more-than and less-than symbols like this "««bookmarkname»»" to make it easier to parse.
Here is my code:
Sub new_test()
Dim sT As String
Dim boo As Boolean
boo = False
Selection.Find.ClearFormatting
With Selection.Find
.Text = "««*»»[ ]"
.Forward = False
.Wrap = wdFindContinue
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchAllWordForms = False
.MatchSoundsLike = False
.MatchWildcards = True
Do While .Execute
With Selection
'sT = Selection.Text
If (boo = False) Then
MsgBox "Added a character after bookmark"
Selection.InsertAfter (" ")
boo = True
End If
End With
boo = False
Loop
End With
End Sub
Ok - worked it out. Maybe it will prove of some use to someone.
Before I run this, I run another function over the document that reveals all of the bookmarks and puts more and less than signs around them like this: "««BOOKMARKNAME»»"
Sub bookmarks_ensure_space_beforeAfter()
' Before we can do any work, we need a list of bookmarks from the document
Dim bmks As Variant
bmks = create_array_of_bookmark_names() ' array of bookmark names
' This Assumes that there will not be more than 1000 bmks in the array fetched from the Word Doc
For i = 0 To 1000
If (bmks(i) <> "") Then
' if the 'bmk' is not null then process it
' there are likely to be several 100 that are empty
Dim wrd As String
Dim rng As Range
Call select_a_string("««" & bmks(i) & "»»") ' select the bookmark
wrd = "««" & bmks(i) & "»»"
Set rng = Selection.Range
' now move the cursor two places the left of the bookmark
Selection.MoveLeft Unit:=wdCharacter, count:=2
' now select the character infront of the cursor (which is now the character infront of the bmk)
Selection.MoveRight Unit:=wdCharacter, count:=1, Extend:=wdExtend
If (Selection.Text <> " ") Then
' if this character now selected is not a space - add one
rng.InsertBefore " "
End If
' now move the cursor to the right of the bookmark (using it's length as a character limit)
Selection.MoveRight Unit:=wdCharacter, count:=Len(wrd) + 1
' due to bookmarks being fiddly, recreate the same bmk directly after the original
With ActiveDocument.Bookmarks
.Add Range:=Selection.Range, Name:=bmks(i)
.DefaultSorting = wdSortByName
.ShowHidden = False
End With
' now we have a new bmk, select the character directly after the bmk)
Selection.MoveRight Unit:=wdCharacter, count:=1, Extend:=wdExtend
If (Selection.Text <> " ") Then
' if this character now selected is not a space - add one
rng.InsertAfter " "
End If
End If
Next
End Sub
Function create_array_of_bookmark_names() As Variant
' This function creates an array of bookmarks in the document and returns them as an array
Dim array_of_bmk(1000) As Variant
Dim c As Integer
c = 0
For Each mBookmark In ActiveDocument.Bookmarks()
array_of_bmk(c) = mBookmark.Name
c = c + 1
Next
' now return this array
create_array_of_bookmark_names = array_of_bmk
End Function
Sub select_a_string(str)
' This finds and selects a string of characters
Selection.Find.ClearFormatting
With Selection.Find
.Text = str
'.Replacement.Text = ""
.Forward = True
.MatchCase = True
.Wrap = wdFindContinue
.Format = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
End With
Selection.Find.Execute
End Sub
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