VBA: Replace text based on formatting - vba

I have a table in a Word file A which contains a bunch of different Contents. Which I just copy using VBA into another Word or PowerPoint file B. So far that is not a problem.
However, since file A is a working sheet, people sometimes cross stuff out, which means: it should be removed, but for the record it stays in there first. In the final version it shouldnt be displayed, so in the process of copying everything in a different file, the crossed out text should be removed.
To break it down to the technical stuff:
I want to select text in a Word document, and then remove all text that has a certain formatting.
Maybe there is a special selection possibility or a way to iterate through all characters and test for formatting.

The best way to do this without suffering severe performance iterating characters or paragraphs in vba is to use find and replace.
You can do this in vba as follows, note I have wrapped all the actions in a custom undo record, then you can call your current vba routine with CopyDocumentToPowerPoint and the word document will be restored to the state it was before the macro ran (crossed out text remains in word, but is not pasted to powerpoint).
'wrap everything you do in an undo record
Application.UndoRecord.StartCustomRecord "Move to powerpoint"
With ActiveDocument.Range.Find
.ClearFormatting
.Font.StrikeThrough = True
.Text = ""
.Replacement.Text = ""
.Execute Replace:=wdReplaceAll
End With
'copy to powerpoint and whatever else you want
CopyDocumentToPowerPoint
Application.UndoRecord.EndCustomRecord
'and put the document back to where you started
ActiveDocument.Undo

It is possible to go character-by-character and remove those which have the strikethrough font enabled on them (the ones which are crossed out) in MS Word. However, as far as I know, there is no such possibility to detect a strike-through font in MS PowerPoint.
If you just need to delete the text which has the strikethrough font on it in the selected text only, you can use this Word macro:
Sub RemoveStrikethroughFromSelection()
Dim char As Range
For Each char In Selection.Characters
If char.Font.StrikeThrough = -1 Then
char.Delete
End If
Next
End Sub
If more integrated to copying a Word table to another Word document and PowerPoint presentation, the following code might be useful. It first pastes the table to a new Word file, then removes unnecessary characters, and after that pastes this new table to PowerPoint.
Sub CopyWithoutCrossedOutText()
Dim DocApp As Object: Set DocApp = CreateObject("Word.Application")
Dim PptApp As Object: Set PptApp = CreateObject("PowerPoint.Application")
Dim Doc As Object: Set Doc = DocApp.Documents.Add
Dim Ppt As Object: Set Ppt = PptApp.Presentations.Add
Dim c As Cell
Dim char As Range
DocApp.Visible = True
PptApp.Visible = True
'Copying Word table to the 2nd Word document
ThisDocument.Tables(1).Range.Copy
Doc.ActiveWindow.Selection.Paste
'In the 2nd Word document - removing characters having strikethrough font enabled on them
For Each c In Doc.Tables(Doc.Tables.Count).Range.Cells
For Each char In c.Range.Characters
If char.Font.StrikeThrough = -1 Then
char.Delete
End If
Next
Next
'Copying the table from the 2nd Word document to the PowerPoint presentation
Doc.Tables(1).Range.Copy
Ppt.Slides.Add(1, 32).Shapes.Paste
End Sub

Related

How can i change every occurence of a specific font ind a Word document?

i have following problem. Im currently creating a Macro that gets every font thats been used in a Word document. Afterwards it checks, if this font is even installed and changes the font into predefined fonts. (As the Microsoft auto-font-change in Word is pretty bad and changes my fonts into Comic Sans (no joke ...).
Everything works as intended except for one thing.
This here is the code i am using to exchange every occurence of the found
font in the document:
For i = 0 To UBound(missingFont)
For Each oCharacter In ActiveDocument.Range.Characters
If oCharacter.Font.name = missingFont(i) Then
oCharacter.Font.name = fontToUse
If InStr(missingFont(i), "bold") Then
oCharacter.Font.Bold = True
End If
If InStr(missingFont(i), "italic") Then
oCharacter.Font.Italic = True
End If
End If
Next oCharacter
Next i
So basically im checking every Character in my document and change it if needed. Now this only works for Characters that are not inside of textfields, the header or footer. How can i check every, EVERY, character inside of the Document?
First i've tried to use ActiveDocument.Range.Paragraphs instead of ActiveDocument.Range.Characters. I've also tried using the macro given here: http://www.vbaexpress.com/forum/showthread.php?55726-find-replace-fonts-macro but couldnt get this to work at all.
It's not clear what is meant by "textfield" as that could be any of five or six different things in Word...
But there is a way to access almost everything (excluding ActiveX controls) in a Word document by looping all StoryRanges. A StoryRange includes the main body of the document, headers, footers, footnotes, text ranges in Shapes, etc.
The following code sample demonstrates how to loop all the "Stories" in a document. I've put the code provided in the question in a separate procedure that's called from the "Stories" loop. (Note that I am not able to test, not having access to either the documents or relevant portions of code used in the question.)
Sub ProcessAllStories()
Dim doc as Word.Document
Dim missingFont as Variant
Dim myStoryRange as Word.StoryRange
'Define missingFont
Set doc = ActiveDocument
For Each myStoryRange In doc.StoryRanges
CheckFonts myStoryRange, missingFont
Do While Not (myStoryRange.NextStoryRange Is Nothing)
Set myStoryRange = myStoryRange.NextStoryRange
CheckFonts myStoryRange, missingFont
Loop
Next myStoryRange
End Sub
Sub CheckFonts(rng as Word.Range, missingFont as Variant)
Dim oCharacter as Word.Range
For i = 0 To UBound(missingFont)
For Each oCharacter In rng.Characters
If oCharacter.Font.name = missingFont(i) Then
oCharacter.Font.name = fontToUse
If InStr(missingFont(i), "bold") Then
oCharacter.Font.Bold = True
End If
If InStr(missingFont(i), "italic") Then
oCharacter.Font.Italic = True
End If
End If
Next oCharacter
Next i
End Sub

Insert RichText (From RichTextBox, RTF File, OR Clipboard) into Word Document (Bookmarks or Find/Replace)

To summarize what I'm attempting to do, I work for a non-profit organization that sends out acknowledgement letters when someone donates money to us (a thank you, basically). We have multiple different letters that are written every month and sent to IS to "process". I would like to make this as efficient and use as little time as possible for IS, so I've created a program in VB.NET that takes content and pastes it into a template using Word bookmarks, updates a table in SQL so that the letter can be tested with live data, and sends an e-mail to the Production department letting them know to test the letter. It works fully, except...
I cannot for the life of me figure out how to retain RTF (RichText) when I insert the content into the letter template.
I've tried saving the content of the RichTextBox as an RTF file, but I can't figure out how to insert the RTF file contents into my document template and replace the bookmark.
I've tried using the Clipboard.SetText, odoc......Paste method, but it's unreliable as I can't accurately state where I'd like the text to paste. The find/replace function isn't very helpful because all of the bookmarks I'm trying to replace are within text boxes.
I'd show some code, but most of it has been deleted out of frustration for not working. Either way, here's some code I've been working with:
Private Sub testing()
strTemplateLocation = "\\SERVER\AcknowledgementLetters\TEST\TEMPLATE.dot"
Dim Selection As Word.Selection
Dim goWord As Word.Application
Dim odoc As Word.Document
goWord = CreateObject("Word.Application")
goWord.Visible = True
odoc = goWord.Documents.Add(strTemplateLocation)
Clipboard.Clear()
Clipboard.SetText(txtPreD.Rtf, TextDataFormat.Rtf)
odoc.Content.Find.Execute(FindText:="<fp>", ReplaceWith:=My.Computer.Clipboard.GetText)
'Code for looping through all MS Word Textboxes, but didn't produce desired results
For Each oCtl As Shape In odoc.Shapes
If oCtl.Type = Microsoft.Office.Core.MsoShapeType.msoTextBox Then
oCtl.TextFrame.TextRange.Text.Replace("<fp>", "Test")
goWord.Selection.Paste()
End If
Next
'Clipboard.Clear()
'Clipboard.SetText(txtPostD.Rtf, TextDataFormat.Rtf)
'odoc.Content.Find.Execute(FindText:="<bp>", ReplaceWith:="")
'goWord.Selection.Paste()
MsgBox("Click Ok when finished checking.")
odoc.SaveAs2("\\SERVER\AcknowledgementLetters\TEST\TEST.docx")
odoc = Nothing
goWord.Quit(False)
odoc = Nothing
goWord = Nothing
End Sub
...and here is the default code for setting bookmarks. This works perfectly as long as formatting is not required:
Private Sub SetBookmark(odoc As Object, strBookmark As String, strValue As String)
Dim bookMarkRange As Object
If odoc.Bookmarks.Exists(strBookmark) = False Then
Exit Sub
End If
bookMarkRange = odoc.Bookmarks(strBookmark).Range
If ((Err.Number = 0) And (Not (bookMarkRange Is Nothing))) Then
bookMarkRange.text = strValue
odoc.Bookmarks.Add(strBookmark, bookMarkRange)
bookMarkRange = Nothing
End If
End Sub
TL;DR - Need formatted text (Example: "TEST") to be inserted into a Word document either as a bookmark or as a replacement text.
Expected results: Replace "fp" (front page) bookmark with "TEST" including bold formatting.
Actual results: "fp" is not replaced (when using clipboard and find/replace method), or is replaced as "TEST" with no formatting.
I figured it out! I had to do it a weird way, but it works.
The following code saves the RichTextBox as an .rtf file:
RichTextBoxName.SaveFile("temp .rtf file location")
I then used the following code to insert the .rtf file into the bookmark:
goWord.ActiveDocument.Bookmarks("BookmarkName").Select()
goWord.Selection.InsertFile(FileName:="temp .rtf file location")
I then deleted the temp files:
If My.Computer.FileSystem.FileExists("temp .rtf file location") Then
My.Computer.FileSystem.DeleteFile("\temp .rtf file location")
End If

VBA: Can't change SubAddress property of Hyperlinks in Word Document

I'm trying to fix the hyperlinks in a Word document. I need to change the SubAddress property of some hyperlinks. To that end, I'm looping through them. Unfortunately, I get a very weird error saying method 'subaddress' of object 'hyperlink' failed when I try to change any SubAddress. Apparently this happens because something is broken with VBA itself.
Sub FixHyperlinks()
'
' FixHyperlinks Macro
'
'
ActiveDocument.Hyperlinks(1).SubAddress = "some new subaddress"
End Sub
I'm rocking Office 2016 Professional Plus. Can anybody tell me if this works for you?
It's easy to test. Just create a new document, type two one-word lines. Make the second line style "Heading 1". Go to first line, hit CTRK + K (to create hyperlink) point it to "a place in this document", select the heading you just created. DO NOT enter any address. Now go to Macros, paste the above and hit F5 while your caret is inside the code.
The hyperlink works fine when clicked with the mouse (first line hyperlink will take you to the 2nd line Heading).
Although Hyperlink.SubAddress Property is supposed to be a read/write string, writing to it fails - even in Word 2010. Try something along the lines of:
Dim Rng As Range, StrAddr As String, StrTxt As String
With ActiveDocument
With .Hyperlinks(1)
Set Rng = .Range
StrAddr = .Address
StrTxt = .TextToDisplay
.Delete
End With
.Hyperlinks.Add Anchor:=Rng, Address:=StrAddr, SubAddress:="new_sub_address"
End With

Select and format pasted article in word

I have many occasions that I have to copy article from web-page, paste to word and format in a certain way. I had this code to auto paste and format. However, it only work once, and it just doesn't change the font of the pasted article later on.
Sub Macro1()
Dim artic As Word.Range
Set artic = Selection.Range
'keep bold word bold and avoid paragraphs to cluster into one
artic.PasteAndFormat (wdFormatOriginalFormatting)
'paste and select pasted article
artic.Select
artic.Font.Name = "Calibri"
artic.Font.Size = 10.5
artic.Font.Italic = False
artic.ParagraphFormat.Alignment = wdAlignParagraphLeft
End Sub
If you set a breakpoint at artic.Font.Name = "Calibri" so that the code stops after artic.Select you'll see that the Paste method does not include what's been pasted. Generally, artic will be at the beginning of the pasted content.
This means the code needs to be able to locate the position just after where the Selection was before pasting. It also depends on whether the paste occurs at the end of the document, or not.
The following sample code worked for me in my tests. It uses two Ranges: one for where the content will be pasted, the other for the end position after pasting.
(Responding to request for more clarification about the Word object model): Think of a Range object like a selection, with the difference that there can be many Range objects, but only one Selection. When manipulating a Range it often helps to think of using the keyboard to reduce or expand it. Pressing the left- or right-arrow keys will "collapse" a selection to an insertion point; holding Shift and pressing these keys will expand/reduce a selection; holding Shift while clicking somewhere else in the document will also do that. Think of setting Range.Start or Range.End as the equivalent of this last. The start or end point of the Range is being arbitrarily set to another location in the document.
In the case of the first If in the code below the Range is being reduced/collapsed to its starting point (think left-arrow key), then moved one character to the right (think right-arrow key). This puts it beyond where new material will be pasted, so extending the paste point's end to this Range's starting point will pick up everything between the two.
Sub TestPasteAndSelect()
Dim artic As Word.Range, rng As Word.Range
Dim bNotAtEnd As Boolean
Set artic = Selection.Range
Set rng = artic.Duplicate
rng.End = ActiveDocument.content.End
If rng.Characters.Count > 1 Then
'selection is not at end of document
rng.Collapse wdCollapseStart
rng.MoveStart wdCharacter, 1
bNotAtEnd = True
End If
'keep bold word bold and avoid paragraphs to cluster into one
artic.PasteAndFormat (wdFormatOriginalFormatting)
'paste and select pasted article
'artic.Select
'rng.Select
If bNotAtEnd Then
artic.End = rng.Start
Else
Set artic = rng.Duplicate
End If
artic.Font.Name = "Calibri"
artic.Font.Size = 10.5
artic.Font.Italic = False
artic.ParagraphFormat.Alignment = wdAlignParagraphLeft
End Sub

Check Word 2007 bookmark content and do something if it exists

Is it possible to search the content inside a bookmark and if it exists, do something.
For example, if there is a word document with a bookmark named Bookmark1. The enclosing text for Bookmark1 was created by highlighting the the text "Entered Text Goes Here". I want to create a macro that will check to see if the text inside the bookmark was changed, and if NOT, delete the text, the bookmark, the section break before it.
The code below does this except that it deletes the bookmark even if the text is different because it is looking for the name of the bookmark, not its content.
If ActiveDocument.Bookmarks.Exists("Bookmark1") = True Then
ActiveDocument.Bookmarks("Bookmark1").Select
Selection.Delete
With Selection
.EndKey Unit:=wdStory
.TypeBackspace
.Delete
End With
End If
I really want the If statement to say something like:
If the text inside the Bookmark1 = "Entered Text Goes Here" Then do all the stuff below, else quit.
Ideas anyone?
Word 2007.
The below should work if your document is set up how I think it is, otherwise you will need to have a play around with it:
'TestTxt is the default text in the bookmark (assuming that you are not including the paragraph mark in the bookmark)
Dim TestTxt As String: TestTxt = "Enter text here"
'DMRng is the range of the the bookmark you are looking at
Dim BMRng As Range: Set BMRng = ThisDocument.Bookmarks("Bookmark1").Range
If BMRng.Text = TestTxt Then
'Start is the beginning of the bookmark - 1 (as the character before hand should be your section break?!)
BMRng.SetRange Start:=BMRng.Start - 1, End:=BMRng.End
BMRng.Delete
End If