Replacing reference with endnote text in Word - vba

I have a text in Word that includes references (1,2,3,...) to endnotes. There are multiple references to the same endnote (for example there are several 1s) created by cross-referencing.
I would like to replace all references with endnote text.
On the internet I have found a code that does that. The problem is that if there are several references to the same endnote, only reference whose position is the first in the document gets to be replaced with text (for example only the first 1, other 1s don't).
I need help how to replace all references with the appropriate endnote text.
Sub endnotes2()
Dim Note As Endnote
Dim NoteReference As String
Dim NoteText As String
For Each Note In ActiveDocument.Endnotes
With Note
NoteText = .Range.Text
NoteReference = .Index
Call Selection.SetRange(.Reference.End, .Reference.End)
Selection.Font.Superscript = True
Selection.TypeText (NoteText)
Selection.Font.Superscript = False
End With
Next Note
Do While ActiveDocument.Endnotes.Count > 0
Call ActiveDocument.Endnotes(1).Delete
Loop
Selection.Find.ClearFormatting
Selection.Find.Font.Superscript = True
Selection.Find.Replacement.ClearFormatting
Selection.Find.Replacement.Font.Superscript = False
With Selection.Find
.Text = ""
.Replacement.Text = " (^&)" 'The ^& here refers to the "found text", so if we found "abc" we will replace it with "(abc)"
.Forward = True
.Wrap = wdFindContinue
.Format = True
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
End With
Selection.Find.Execute Replace:=wdReplaceAll
End Sub

The following works for me in my simple test.
Since the cross-reference to an endnote does not use superscript by default searching superscript is not a reliable criterium. Also, other things could be superscripted. Cross-references are managed by Word using Ref fields, and these refer to a bookmark placed at the endnote reference when the Insert cross-reference commmand is used.
Such bookmarks begin with _Ref followed by a longish number. And the fields for endnotes use the name NoteRef. So it makes sense to get the bookmark name(s) for the endnote references (there could be more than one), check that they're named using the _Ref pattern then search the document for use of the bookmark(s).
In order to "Find" a field code the pattern ^d is used. So the search term is that, followed by the name of the field code (NoteRef) and the bookmark name. If the search is successful, the field code is deleted and the endnote text is written at this position. The search then continues from this point to the end of the document.
So the code loops through all the endnotes, gets each one's Reference, gets all of its bookmarks, loops the bookmarks, checking the name (as described above) and searches for the NoteRef fields (as described above).
Finally, the original endnote reference is replaced by the endnote text.
Sub WriteEndNoteToAllEndNoteRefs()
Dim sEndNoteText As String
Dim rngEndNoteRef As Word.Range, rngSearch As Word.Range
Dim doc As Word.Document
Dim en As Word.Endnote
Dim bkm As Word.Bookmark
Dim bFound As Boolean
Set doc = ActiveDocument
For Each en In doc.Endnotes
Set rngEndNoteRef = en.Reference
sEndNoteText = en.Range.Text
For Each bkm In rngEndNoteRef.Bookmarks
If Left(bkm.Name, 4) = "_Ref" Then
Set rngSearch = doc.content
rngSearch.TextRetrievalMode.IncludeFieldCodes = True
Do
With rngSearch.Find
.Text = "^d NoteRef " & bkm.Name
.wrap = wdFindStop
bFound = .Execute
If bFound Then
rngSearch.Fields(1).Delete
rngSearch.Text = sEndNoteText
rngSearch.End = doc.content.End
End If
End With
Loop While bFound
End If
Next
rngEndNoteRef = sEndNoteText
Next
End Sub

Related

How replace word tables chr(13)?

I am working on copy and past the word tables to excel. but there are a lot of 'enter' key in word tables. could I know how to replace the the enter key in whole word tables.
I am encountering issue" wrong number of argument or invalid property assignment"
You have more than one problem with this code.
The first is that you are not setting oLookWordDoc to point to a document, so none of the Word code will work.
Second, you have two variables pointing to the same table, oLookwordTbl and r. You only need one of these.
Third, you are selecting the table to run Find instead of simply using the Find method of Table.Range.
Fourth, your find and replacement texts are incorrect.
The tidied code below will replace the paragraph marks in the table with a space.
Dim oLookWordDoc As Word.document
Dim oLookwordTbl As Word.Table
Dim iRow As Long 'row index
'you need to set oLookWordDoc to point to a document here
'Grab the word table
Set oLookwordTbl = oLookWordDoc.Tables(1)
With oLookwordTbl.Range.Find
.Text = "^p"
.Replacement.Text = " "
.Forward = True
.Wrap = wdFindStop
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
.Execute Replace:=wdReplaceAll
End With
'rows 2 - end
For iRow = 2 To oLookwordTbl.Rows.Count
oLookwordTbl.Rows(iRow).Range.Copy
'Paste
xWs.Paste
xWs.Cells(xWs.Rows.Count, 1).End(3).Offset(1).Select
Next
With Selection.find references the Excel selection object. But you want to work with the Word selection object.
Do you have a variable for the word application, e.g. appWord?
Use this: With appWord.Selection.find
If not With oLookWordDoc.parent.selection.find should work

Howto set Range to third Heading1 style match?

I have a document where I want to start start searching in section 3 to the end of the document and bold text based on my user-defined style since other styles used may contain the same word I don't want to bold - including the possibility of the Heading/section.
I do have VBA code that works by finding my user-defined style throughout the document and bolding it for one style match only. However, the .Style in the .find doesn't allow one to specify a wildcard style i.e. my user-defined style set of "Requirement1 thru Requirement9" which are based off the Heading1-9 style. I assume I'll have to create a for loop outside of the "with" that finds my user-defined style that is passed one at a time to bold the text to match one style at a time i.e Requirement1 thru Requirement9. Is there a better way? see code below.
The next issue is to focus the search of this text to bold to start in a particular section to the end of the document. For me, its section 3 to the end of the document or till it encounters another style defined as Appendix1 and stop. I do have user-defined styles Appendix1 thru Appendix9 that are also based off of Heading1-9. The reason to search on a style as a starting point is because these other sections before section3, or descriptive text in Section 3 and beyond may contain the word I'm trying to bold - which I don't want to do except when my particular user-defined style Requirment1-9 was applied that is used in section 3 and beyond. In trying to implement this part before doing the word searching and bolding part, I've been searching based on the "Heading1" style and when I found the third one, I know I'm in section 3. I can't use the VBA "sections" search since it includes all the subsections of a document which can vary from document to document and specifying sections.item(3) doesn't mean I'll get the third section of my document that corresponds to the third Heading1 style.
Since I'm not that adept at the various VBA sections,paragraphs,sentences, characters and everything else when applying the "range" either before, after, or both on any of these (never seems to work the way one expects. Even the VBA hint tools says one can do it, but runtime says error) I've started with the specifying the start/end of the whole activedocument.range. Then I perform a ".find" of the "Heading1" style in a for loop three times which does find them. I then try to assign the last Heading1 found range value as the start value to use in the next embedded "find" that will search and apply the bold to the "Requirement1" style. (May need to create a loop to search Requirement1-9 styles as stated above). To help me know where I'm at, I'm trying to dump via debug.print the range position, but it dumps the all whole document text to the debug window and not the integer value I thought I'd get. Whats the issue with doing this? I've even tried to use a selection.range and dump the retrieved text to the debug.print window without success. It makes it worse since the processing timing seems to run forever. The wdFindStop doesn't force the find to stop on the third find either.
So how to:
a). find and dump the range position to the debug window along with the text at this position. Both the number and text will tell me where I'm at.
c). How to assign the range position based on find of the third "Heading1" position in the document so that that the second "with" can search and apply the bolding to the text I want to bold.
d). How to do a wildcard search on the .Style user-defined Requirement1-9 style instead of having to create a for loop to search one at a time?
The following is the VBA code I have written.
Attribute VB_Name = "BoldMustShall2_M"
Option Explicit
Public Sub BoldMustShall2()
' If .Parent.Bold = True is used with wdReplaceall, the whole
' document is bolded even when the sentence doesn't have any of the words
' being searched for.
Dim myRange, rngSel As Range
Dim oDoc As Word.Document
Dim pos1, pos2 As Long
Dim numchars As Long
Set oDoc = ActiveDocument
Set rngSel = Selection.Range
Application.ScreenUpdating = False
'Set the starting Heading to search as Section 3
pos1 = oDoc.Range.Start
pos2 = oDoc.Range.End
Set myRange = oDoc.Range(Start:=pos1, End:=pos2)
'Another way is to find the "Heading1" style and set the range start to the third one found which is section 3.
'Counting Word sections can vary alot so its not the best way.
'The same would apply if Appendix1 style is used and assuming that requiremens start in the third one.
Debug.Print "My Start Range " + myRange
With myRange
.TextRetrievalMode.IncludeFieldCodes = False ' don't want to search fieldcodes for must/shall
.TextRetrievalMode.IncludeHiddenText = False ' don't want to search hiddentext for must/shall
' Get the range position for Heading1 style for section 3 of PRD.
Dim i As Integer
Dim ReqHDR As Range
Dim bFind As Boolean
With .Find
.ClearFormatting
.Forward = True
'.Wrap = wdFindStop
.Format = False
.MatchCase = False
.MatchWholeWord = True
.MatchWildcards = False
.Style = "Heading1"
'Loop three times for Style
For i = 1 To 3 Step 1
'bFind = .Execute
.Execute Wrap:=wdFindStop
If .Found = True Then
rngSel = oDoc.Range 'This should be the current position in the Document for the requirements.
' When found it outputs the message once
Debug.Print "Found a Heading1 style "
.Replacement.Font.Size = 20
End If
'.Wrap = wdFindStop
Next i
End With
Debug.Print "End of Heading1 Search "
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Forward = True
.Wrap = wdFindContinue
.Format = False
.MatchCase = False
.MatchWholeWord = True
.MatchWildcards = False
.Replacement.Font.Bold = True
.Replacement.Font.Name = "Times New Roman"
.Replacement.Font.Size = 12
.Replacement.Font.Italic = True
'.Style = "Requirement1" ' A loop is needed to cycle thru all the Requirement1-9 styles. No wildcard.
'.Style = wdStyleNormal
.Replacement.Text = "^&" ' This is the contents of the find what box in word.
' In this case the .find.text "must" statement.
' Alternate is to specify "must" or "shall" but this
' would require two replace.text statements instead of
' just this one. The ^& is a special command that eliminates
' the need to set the replacement.Text info.
'.Text = "must"
.Execute FindText:="must", Replace:=wdReplaceAll
If .Found = True Then
' When found it outputs the message once
Debug.Print "Found one or more must "
End If
'.Text = "shall"
.Execute FindText:="shall", Replace:=wdReplaceAll
If .Found = True Then
' When found it outputs the message once
Debug.Print "Found one or more shall "
End If
End With
End With
Application.ScreenUpdating = True
Debug.Print "Completed searching for must/shall in document."
End Sub
Assuming that, when you refer to 'Sections', you're referring to parts of your document delineated by Section breaks, perhaps something along the lines of:
Sub Demo()
Application.ScreenUpdating = False
Dim Rng As Range, i As Long
With ActiveDocument
Set Rng = .Range(.Sections(3).Range.Start, .Range.End)
With .Range
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = ""
.Replacement.Text = ""
.Forward = True
.Format = True
.Wrap = wdFindContinue
.Style = "Appendix1"
.Execute
End With
Rng.End = .Start
End With
With Rng.Find
.ClearFormatting
.Replacement.ClearFormatting
.Forward = True
.Format = True
.Replacement.Style = "Strong"
.Wrap = wdFindStop
.Replacement.Text = "^&"
.Text = "must"
For i = 1 To 9
.Style = "Requirement" & i
.Execute Replace:=wdReplaceAll
Next
.Text = "shall"
For i = 1 To 9
.Style = "Requirement" & i
.Execute Replace:=wdReplaceAll
Next
End With
End With
Application.ScreenUpdating = True
End Sub
Note that, instead of using hard formatting for the replacement, I've simply applied Word's built-in 'Strong' Style. Your own code should use a Style, too, whether it's Word's 'Strong' Style or another character Style of your own definition.

Word 2016/VBA Highlight first use of each word from a word list

I am working on a macro for Word that accesses a separately saved doc file with a long word list of several pages. The word list doc is formatted like,
FMS
CPR
Abc
...to separate each word by the line break.
The macro needs to highlight the first use of each word from the list.
Right now, the macro highlights every use of the word, and in addition, highlights that word when it's part of another word. For example, it highlights EZE in the word freeze, but it should only highlight when eze stands alone.
Can someone help with how to,
1. highlight first-use only, and
2. how to make sure it's only catching the actual word, not all the other words that contain that word? I can't seem to make that happen with VBA.
My current code:
Sub TD()
'
Dim sCheckDoc As String
Dim docRef As Document
Dim docCurrent As Document
Dim wrdRef As String
Dim wrdPara As Paragraph
sCheckDoc = "c:\check.docx"
Set docCurrent = Selection.Document
Set docRef = Documents.Open(sCheckDoc)
docCurrent.Activate
With Selection.Find
.ClearFormatting
.Replacement.ClearFormatting
.Replacement.Highlight = True
.Replacement.Text = "^&"
.Forward = True
.Format = True
.MatchWholeWord = True
.MatchCase = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
End With
For Each wrdPara In docRef.Paragraphs
wrdRef = wrdPara.Range.Text
If Asc(Left(wrdRef, 1)) > 32 Then
' remove the paragraph mark:
wrdRef = Left(wrdRef, Len(wrdRef) - 1)
With Selection.Find
.Wrap = wdFindContinue
.Text = wrdRef
.Execute Replace:=wdReplaceAll
End With
End If
Next wrdPara
docRef.Close
docCurrent.Activate
End Sub
Try wdReplaceOne instead wdReplaceAll.
.MatchWholeWord = True should prevent highlighting embedded strings but it seems to be ignored.
I tested your original code in module behind ThisDocument and it highlighted all instances of only the last string from check document, ignoring the MatchWholeWord parameter. After the suggested edit, the code highlighted first instance of only the last string from check document. Now I can't get the procedure to work. It runs but words do not highlight. I've never used VBA behind Word. Hope this change works for you.

Remove all text between 2 headers Word 2010, using VBA

I have 2 headers or markers that are a part of my RTF document. In my example I am showing a sentence when in reality it will be multiple sentences or paragraphs. I have used brackets instead of less than and greater than signs as they disappear in my question. All I want to do is replace the text between the 2 markers with the following sentence, "text goes here", without quotation marks.
[EmbeddedReport]Lots of text, thousands of character, multiple paragraphs[/EmbeddedReport]
I want replace all the text between the 2 markers replaced with "text goes here".
It would end up looking like this...
"[EmbeddedReport]text goes here[/EmbeddedReport]"
I've literally spent 2 days trying to solve this. Any help would be appreciated.
This is the last thing I tried...
Sub RemoveReport()
Dim c As Range
Dim StartWord As String, EndWord As String
Selection.HomeKey Unit:=wdStory
StartWord = "<ImageTable>"
EndWord = "</ImageTable>"
Set c = ActiveDocument.Content
c.Find.ClearFormatting
c.Find.Replacement.ClearFormatting
With c.Find
.Text = StartWord & "*" & EndWord
' MsgBox (.Text)
.Replacement.Text = "<ImageTable>text goes here</ImageTable>"
.Forward = True
.Wrap = wdFindStop
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = True
.MatchSoundsLike = False
.MatchAllWordForms = False
End With
c.Find.Execute
While c.Find.Found
Debug.Print c.Text
'~~> I am assuming that the start word and the end word will only
'~~> be in the start and end respectively and not in the middle
Debug.Print Replace(Replace(c.Text, StartWord, ""), EndWord, "")
c.Find.Execute
Wend
End Sub
Word VBA is not my area of expertise, but it seems similar to a question I answered a few days ago.
Turns out the wildcard match was not doing what I hoped it would do, or at least it was not reliable. Also, I ran in to some trouble using angle brackets, so this uses square brackets. I suspect that word treats the angle brackets as markup/syntax, and thus does not interpret them as text in the Find object. There is probably a way around this, but Word VBA is not my specialty. There is also probably a more elegant solution, but again, Word VBA is not my specialty :)
Try something like this:
Option Explicit
Sub Test()
Dim doc As Document
Dim txtRange As Range
Dim startTag As String
Dim endTag As String
Dim s As Long
Dim e As Long
startTag = "[EmbeddedReport]"
endTag = "[/EmbeddedReport]"
Set doc = ActiveDocument
Set txtRange = doc.Content
'Find the opening tag
With txtRange.Find
.Text = startTag
.Forward = True
.Execute
If .Found Then
s = txtRange.Start
Else
GoTo EarlyExit
End If
End With
'Find the closing tag
Set txtRange = doc.Range(txtRange.End, doc.Content.End)
With txtRange.Find
.Text = endTag
.Forward = True
.Execute
If .Found Then
e = txtRange.End
Else
GoTo EarlyExit
End If
End With
Set txtRange = doc.Range(s, e)
txtRange.Text = startTag & "text goes here" & endTag
Exit Sub
EarlyExit:
MsgBox "Header not found in this document!", vbInformation
End Sub
It takes some time to figure it out at first, but learning to navigate the object model reference documentation for VBA will make these tasks a lot easier to figure out in the future.

Find Numerals in Text and insert vbCr immediately before Numerals

I have a word document with numerical references spread throughout the body of my text. For example "text string 1" ###:### "text string 2". Note the colon in the middle of the numberical reference. The numerical references may range from 1-999 on either side of the colon, but every reference has at least one number on each side of the colon with no more than 3 numbers on either side.
I need a routine that scans the entire document, identifies each numeral reference and then enters a carriage return BEFORE the numerical reference.... so every numerical reference would start a paragraph in the document. To illustrate this, the example above would be transformed to...
"Text string 1"
"###:###" "Text String 2"
I've tried modifying a Find/Replace operation to do this (to the point I'm going cross eyed) but can't seem to figure it out.
Any help would be greatly appreciated. Thank you!
I think using RegExp is a bit complicated here as long as there is Find-Replace feature in MS Word. Try with this code:
Sub Find_Replace_Macro()
Selection.Find.ClearFormatting
Selection.Find.Replacement.ClearFormatting
With Selection.Find
.Text = "([ ])([0-9]{1;3}:[0-9]{1;3})" 'solution for non-English version of MS-Word
.Text = "([ ])([0-9]{1,3}:[0-9]{1,3})" 'solution for English version of MS-Word
.Replacement.Text = "^13\2"
.Forward = True
.Wrap = wdFindContinue
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchAllWordForms = False
.MatchSoundsLike = False
.MatchWildcards = True
End With
Selection.Find.Execute Replace:=wdReplaceAll
End Sub
You can do this with a simple Regular Expression Replace Function...
Sub TestSub()
Dim StrText
StrText = "Blajdflajdflaj 123:133 lajdflkaj123:343 alkdjflakjd 444:78 alkjdlfajkdlksjalk"
Debug.Print AddNewLine(StrText)
End Sub
Function AddNewLine(strInput)
Dim objRegEx
Set objRegEx = CreateObject("VBScript.RegExp")
objRegEx.IgnoreCase = True
objRegEx.Global = True
objRegEx.Pattern = "\d{1,3}\:\d{1,3}"
'Remove one of the vbCrLf's if you only want a single New Line
AddNewLine = objRegEx.Replace(strInput, vbCrLf & vbCrLf & "$&")
End Function
The above routine will create the below output:
Blajdflajdflaj
123:133 lajdflkaj
123:343 alkdjflakjd
444:78 alkjdlfajkdlksjalk
If your working with a MS Word Document, you can test with:
StrText = ActiveDocument.Content.Text
For some extra reading on Substitutions in Regular Expressions please see:
http://msdn.microsoft.com/en-us/library/ewy2t5e0.aspx