I wrote code in Word to find "[edit]" links in a document, break the hyperlink, and delete the text.
I would like to adapt this to run in Outlook. I have gone to tools>references to allow Outlook to access Word object library, and inserted the following code before my "DeleteEditLinks" macro:
Dim Ins As Outlook.Inspector
Dim Document As Word.Document
Dim Word As Word.Application
Dim Selection As Word.Selection
Set Ins = Application.ActiveInspector
Set Document = Ins.WordEditor
Set Word = Document.Application
Set Selection = Word.Selection
The final code looks like this:
Public Sub DeleteEditLinks()
Dim Ins As Outlook.Inspector
Dim Document As Word.Document
Dim Word As Word.Application
Dim Selection As Word.Selection
Set Ins = Application.ActiveInspector
Set Document = Ins.WordEditor
Set Word = Document.Application
Set Selection = Word.Selection
Dim oField As Field ' breaks hyperlinks of "[edit]" links, and deletes them
For Each oField In ActiveDocument.Fields
If oField.Type = wdFieldHyperlink Then
If Left(oField.Result, 4) = "edit" Then
oField.Unlink
End If
End If
Next
Set oField = Nothing
Dim sample
sample = "[edit]"
Selection.Find.ClearFormatting
Selection.Find.Replacement.ClearFormatting
With Selection.Find
.Text = sample
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindContinue
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
End With
Selection.Find.Execute Replace:=wdReplaceAll
End Sub
How do I adapt this to run on the text of an Outlook email?
I'm not sure how Fields object must appear in the outlook, as well as what ecxatly you are trying to achieve, but!.. I've found basic issues in your code, so, my solution might be helpful.
You refer to ActiveDocument within as it is a part of Outlook objects collection. It is not, so you need to refer to the Document object which you've correctly created from inspector. The same with Selection.
I used late binding (Dim oField As Object), not sure if with early binding and "tools>references" option on you also have this trouble, but word constants wdFindContinue were not recognized so I used values for them (just googled them).
So, if in your target e-mails there are fields somehow - your updated code below should work... Please write if not the case.
Public Sub DeleteEditLinks()
Dim Ins As Outlook.Inspector
Dim Document As Object
Dim oField As Object
Dim sample As String
Set Ins = Application.ActiveInspector
Set Document = CreateObject("Word.Document")
Set Document = Ins.WordEditor
For Each oField In Document.Fields
If oField.Type = 88 Then
If Left(oField.Result, 4) = "edit" Then
oField.Unlink
End If
End If
Next
Set oField = Nothing
sample = "[edit]"
Document.Application.Selection.Find.ClearFormatting
Document.Application.Selection.Find.Replacement.ClearFormatting
With Document.Application.Selection.Find
.Text = sample
.Replacement.Text = ""
.Forward = True
.Wrap = 1
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
.Execute Replace:=2
End With
End Sub
Related
First and foremost, I'm a novice at this.
The situation is as follows:
A Word template is being edited by a VBA macro upon generating a document. I need to improve the VBA macro by deleting a set string of text (A) and replacing it with a different string of text (B) upon the condition that another specific string of text (C) can be found in the document.
There's a Boolean function
Function findrange(tekst As String) As Boolean
Set place = Documents(ActiveDocument.Name).Content
If place.Find.Execute(findtext:=tekst) = True Then
findrange = True
Else
findrange = False
End If
End Function
By which I can identify if that string of text (A) is found in the document. So far so good.
What I need is to delete that string of text (A), if it is found in the document, upon the condition that another string of text (C) can be found in the document.
How do I go about it? I've tried
If findrange("C") = True Then
If findrange("A") = True Then place.Text = ""
But If True Then doesn't allow nesting Ifs apparently.
You need to set up two Range variables.
Dim rngA as Word.Range
Dim rngC as Word.Range
Then upon finding the Text(A) using your findRange function you need to store the found range in the rngA variable.
Set rngA = place.Range
Next, run the findRange function again using Text(C), and assuming it is found you can then replace the rngA.text with your Text(B) data.
For example:
Sub Demo()
Application.ScreenUpdating = False
Dim RngA As Range, RngB As Range
With ActiveDocument
Set RngA = .Range: Set RngB = .Range
With RngA.Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = "String C"
.Execute
If .Found = True Then
With RngB.Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = "String A"
.Replacement.Text = "String B"
.Format = False
.Forward = True
.Wrap = wdFindContinue
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
.Execute Replace:=wdReplaceAll
End With
End If
End With
End With
Application.ScreenUpdating = True
End Sub
I am writing a VBA script in Excel which needs to add a table of contents to a pre-existing word document in a specific location.
I have a word document with the following text somewhere in it: [contents_table_placeholder]
I want to find the text [contents_table_placeholder] and replace it with a word document automatic contents table.
However, I am struggling to get the table of contents to appear anywhere other than at the start of the document. My initial approach was to do a find and replace (replacing [contents_table_placeholder] with an empty string). I thought this would place the cursor in the correct place to then add the contents table but unfortunately this method doesn't work.
Sub createContentsPage()
Dim objWord As Word.Application
Dim inputDoc As Word.Document
Dim rngWord As Word.Range
Set objWord = New Word.Application
With objWord
.Visible = True
Set inputDoc = .Documents.Open( _
Filename:="C:\test.docx", _
ReadOnly:=False)
End With
With inputDoc.Content.Find
.Text = "[contents_table_placeholder]"
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindStop
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
.ExecuteReplace:=wdReplaceOne
End With
With inputDoc
Set rngWord = .Range(Start:=0, End:=0)
.TablesOfContents.Add _
Range:=rngWord, _
UseFields:=True, _
UseHeadingStyles:=True, _
LowerHeadingLevel:=2, _
UpperHeadingLevel:=1
End With
Set objWord = Nothing
Set inputDoc = Nothing
Set rngWord = Nothing
End Sub
After other attempts failed, I came up with the following work-around solution which involves creating the table of contents at the top of the document first and then cutting and pasting into the desired location.
Sub createContentsPage()
Dim objWord As Word.Application
Dim inputDoc As Word.Document
Dim rngWord As Word.Range
Set objWord = New Word.Application
With objWord
.Visible = True
Set inputDoc = .Documents.Open( _
Filename:="C:\test.docx", _
ReadOnly:=False)
End With
'Create table of contents at top of document
With inputDoc
Set rngWord = .Range(Start:=0, End:=0)
.TablesOfContents.Add _
Range:=rngWord, _
UseFields:=True, _
UseHeadingStyles:=True, _
LowerHeadingLevel:=2, _
UpperHeadingLevel:=1
End With
'Scroll to top of document
objWord.Selection.HomeKey Unit:=wdStory
'Select contents table
objWord.Selection.MoveRight Unit:=wdCharacter, Count:=1, Extend:=wdExtend
'Cut contents table
objWord.Selection.Cut
'Find placeholder and delete (cursor will remain at place holder)
With inputDoc.Content.Find
.Text = "[contents_table_placeholder]"
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindStop
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
.ExecuteReplace:=wdReplaceOne
End With
'Insert new line
objWord.Selection.TypeParagraph
'Paste contents table
objWord.Selection.PasteAndFormat (wdFormatOriginalFormatting)
inputDoc.Save
inputDoc.Close
Set objWord = Nothing
Set inputDoc = Nothing
Set rngWord = Nothing
End Sub
I get run-time error 13 (Type Mismatch) on my code when I try to run it.
I'm trying to replace a text in a opened Word document through Excel, inside the header.
Set WordApp = CreateObject("Word.Application")
WordApp.Visible = True
Set WordDoc = WordApp.Documents.Open(myPath & "\Armaturförteckning.docx")
' Ändrar i Armaturförteckningen
Dim rngStory As Range
Dim lngJunk As Long
'Fix the skipped blank Header/Footer problem as provided by Peter Hewett
lngJunk = WordApp.ActiveDocument.Sections(1).Headers(1).Range.StoryType
'Iterate through all story types in the current document
For Each rngStory In WordApp.ActiveDocument.StoryRanges
'Iterate through all linked stories
Do
With WordApp.rngStory.Find
.Text = "ELESTATUS01"
.Replacement.Text = "I'm found"
.Wrap = wdFindContinue
.Execute Replace:=wdReplaceAll
End With
'Get next linked story (if any)
Set rngStory = WordApp.rngStory.NextStoryRange
Loop Until rngStory Is Nothing
Next
' Stänger dokumentet
WordApp.Documents.Save
WordApp.ActiveDocument.Close
I believe you are trying to do a VBA search and replace. We have a BUNCH of functions that we use, and after many years of refinement, the following is what we use. It's purely the function that performs a search and replace.
Function SimpleSearchAndReplace(SomeDocument As Word.Document, SearchString As String, ReplaceString As String)
With SomeDocument.Content.Find
.Text = SearchString
.Replacement.Text = ReplaceString
.Forward = True
.Wrap = wdFindContinue
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
.Execute Replace:=wdReplaceAll
End With
End Function
It seems awkward that you have "WordApp.ActiveDocument." when what you probably need is "WordDoc." in your 'lngJunk' and 'For Each' lines.
I am looking for a way to create a new document containing all the text with a specific format from my document.
See below for what I wrote so far, but I'm stuck here:
how do I stop my loop when end of document is reached? or how do I add intelligence to my code to avoid a static loop, and rather do a "scan all my document"?
Option Explicit
Sub Macro1()
Dim objWord As Application
Dim objDoc As Document
Dim objSelection As Selection
Dim mArray() As String
Dim i As Long
Dim doc As Word.Document
For i = 1 To 100
ReDim Preserve mArray(i)
With Selection.Find
.ClearFormatting
.Font.Color = wdColorBlue
.Text = ""
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindStop
.Format = True
.Execute
End With
mArray(i) = Selection.Text
Next
Set objWord = CreateObject("Word.Application")
Set objDoc = objWord.Documents.Add
objWord.Visible = True
Set objSelection = objWord.Selection
For i = 1 To 100
objSelection.TypeText (mArray(i))
Next
End Sub
Thanks to Cindy's nice tip (I could also have found relevant information in Loop through Word document, starting from beginning of file at start of each loop), and in case this could help someone some day:
define the format you are looking for thanks to Word's Macro Recorder
position yourself at the beginning of your document
Use a while loop checking wdFindStop -- It also demonstrate how to use Array of String in VBA--:
...
Sub Macro2()
Dim mArray() As String
Dim i As Long, n As Long
Dim doc As Word.Document
Dim isFound As Boolean
isFound = True
i = 1
'For i = 1 To 40
Do While (isFound)
ReDim Preserve mArray(i)
With Selection.Find
.ClearFormatting
.Font.Color = wdColorBlue
.Text = ""
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindStop
.Format = True
isFound = .Execute
End With
mArray(i) = Selection.Text
i = i + 1
Loop
'Next
n = i - 2
MsgBox n & " occurrences found."
'
' create a new document with the phrases found
Dim objWord As Application
Dim objDoc As Document
Dim objSelection As Selection
Set objWord = CreateObject("Word.Application")
Set objDoc = objWord.Documents.Add
objWord.Visible = True
Set objSelection = objWord.Selection
For i = 1 To n 'mArray's Size
objSelection.TypeText (mArray(i))
objSelection.TypeParagraph
Next
End Sub
NB: I could also have greatly benefited from https://msdn.microsoft.com/en-us/library/office/aa211953%28v=office.11%29.aspx that explains how to find without changing the selection:
With ActiveDocument.Content.Find
.Text = "blue"
.Forward = True
.Execute
If .Found = True Then .Parent.Bold = True
End With
And from here: Find text only of style "Heading 1" (Range.Find to match style)
I happen to have problems trying to manipulate the below code to my liking.
First off, the code below deletes everything in between the start and end conditions I have stipulated in my program.
I would like to change this, to delete everything besides those stipulated between the start and end words.
Sub SomeSub()
Dim StartWord As String, EndWord As String
Dim Find1stRange As Range, FindEndRange As Range
Dim DelRange As Range, DelStartRange As Range, DelEndRange As Range
Application.ScreenUpdating = False
Application.DisplayAlerts = False
'Setting up the Ranges
Set Find1stRange = ActiveDocument.Range
Set FindEndRange = ActiveDocument.Range
Set DelRange = ActiveDocument.Range
'Set your Start and End Find words here to cleanup the script
StartWord = "From: Research.TA#traditionanalytics.com|Tradition Analytics Commentary| | |"
EndWord = "This message has been scanned for malware by Websense. www.websense.com"
'Starting the Find First Word
With Find1stRange.Find
.Text = StartWord
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindAsk
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
'Execute the Find
Do While .Execute
'If Found then do extra script
If .Found = True Then
'Setting the Found range to the DelStartRange
Set DelStartRange = Find1stRange
'Having these Selections during testing is benificial to test your script
DelStartRange.Select
'Setting the FindEndRange up for the remainder of the document form the end of the StartWord
FindEndRange.Start = DelStartRange.End
FindEndRange.End = ActiveDocument.Content.End
'Having these Selections during testing is benificial to test your script
FindEndRange.Select
'Setting the Find to look for the End Word
With FindEndRange.Find
.Text = EndWord
.Execute
'If Found then do extra script
If .Found = True Then
'Setting the Found range to the DelEndRange
Set DelEndRange = FindEndRange
'Having these Selections during testing is benificial to test your script
DelEndRange.Select
End If
End With
'Selecting the delete range
DelRange.Start = DelStartRange.Start
DelRange.End = DelEndRange.End
'Having these Selections during testing is benificial to test your script
DelRange.Select
'Remove comment to actually delete
DelRange.Delete
End If 'Ending the If Find1stRange .Found = True
Loop 'Ending the Do While .Execute Loop
End With 'Ending the Find1stRange.Find With Statement
End Sub
Hah! That's a new twist There's certainly more than one way to go about it; my inclination would be to work with (at least) three Ranges. Something like this:
Sub FindAndDeleteEverythingElse()
Dim strFind1 As String, strFind2 As String
Dim rngDoc As word.Range, rngFind1 As word.Range
Dim rngFind2 As word.Range
Dim bFound As Boolean
strFind1 = "You"
strFind2 = "directly."
Set rngDoc = ActiveDocument.content
Set rngFind1 = rngDoc.Duplicate
Set rngFind2 = rngDoc.Duplicate
With rngFind1.Find
.Text = strFind1
bFound = .Execute
End With
If bFound Then
With rngFind2.Find
.Text = strFind2
bFound = .Execute
End With
If bFound Then
rngDoc.End = rngFind1.Start
rngDoc.Delete
rngDoc.Start = rngFind2.End
rngDoc.End = ActiveDocument.content.End
rngDoc.Delete
End If
End If
End Sub
The "main" Range is that of the entire document: ActiveDocument.Content. The Range object is a bit different than other objects, if you set one Range to another it becomes that Range, not a copy. So you need the Duplicate method to make a copy of a Range. This lets you use Find independently for the various Ranges.
If the first Find is successful, the second one is executed. If that is also successful then the Document Range's end-point is set to the starting point of the successful Find and the content of the Range deleted. The Document Range is then re-defined to start at the end-point of the second found Range and end at the end of the Document, and deleted.
You will probably have to set more Range.Find properties than I did in this code snippet - I used the absolute minimum to make working with the Ranges clearer.
There maybe another way but till then you can do this.
try to add dummy character after and before your string like this
With ActiveDocument.Range
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Forward = True
.Wrap = wdFindContinue
.Format = False
.MatchWildcards = False
.Text = "From: Research.TA#traditionanalytics.com|Tradition Analytics Commentary| | |"
.Replacement.Text = "From: Research.TA#traditionanalytics.com|Tradition Analytics Commentary| | |######"
.Execute Replace:=wdReplaceAll
.Text = "This message has been scanned for malware by Websense. www.websense.com"
.Replacement.Text = "######This message has been scanned for malware by Websense. www.websense.com"
.Execute Replace:=wdReplaceAll
End With
End With
End Sub
Then try to set range between ###### and ######
this is best answer to set range select a range of text from one Word document and copy into another Word document
Please note that in my word 2007 it is not possible to find within hyperlinks. Try to remove all hyperlink or within range before doing replacement.
another best answer for that: How do you remove hyperlinks from a Microsoft Word document?