I have a huge document in which the lines starting with some specific words text style should be changed. I have created an array for all those words and tried formatting the document using For loop. But only the style of first word in the array is getting changed not for all the words in the array.
Below is what I did, please have a look at it and suggest the solution:
Sub Variables_NormalTxt()
Dim oRng As Word.Range
Dim oRngFC As Word.Range
Dim varUbyteNormal As Variant
Dim ArrayItem As String
Dim i As Integer
varUbyteNormal = Array("uword", "ubyte", "bool", "sword", "const", "ulong", "static")
Set oRng = ActiveDocument.Range
i = 0
For i = 0 To UBound(varUbyteNormal)
With oRng.Find
.Text = varUbyteNormal(i)
.Font.Name = "Times New Roman"
.Font.Bold = False
.Font.size = 10
While .Execute
oRng.Select
Set oRngFC = ActiveDocument.Bookmarks("\Line").Range
oRngFC.Style = "variable normal"
Wend
End With
Next i
End Sub
Move this line
Set oRng = ActiveDocument.Range
into the For loop
i.e.
For i = 0 To UBound(varUbyteNormal)
Set oRng = ActiveDocument.Range
With oRng.Find
etc.
Incidentally...
You can remove the line
i = 0
Your For statement can be generalised to
For i = LBound(varUbyteNormal) To UBound(varUbyteNormal)
and perhaps others will suggest other improvements.
( ...a further look suggests the following, but it depends on precisley
what you are looking for)
Sub Variables_NormalTxt3()
Dim oRng As Word.Range
Dim varUbyteNormal As Variant
Dim ArrayItem As String
Dim i As Integer
varUbyteNormal = Array("uword", "ubyte", "bool", "sword", "const", "ulong", "static")
For i = LBound(varUbyteNormal) To UBound(varUbyteNormal)
Set oRng = ActiveDocument.Range
With oRng.Find
.ClearAllFuzzyOptions
.ClearFormatting
.Text = varUbyteNormal(i)
.Font.Name = "Times New Roman"
.Font.Bold = False
.Font.Size = 10
' perhaps also...
.MatchCase = False
While .Execute
oRng.Style = "variable normal"
Wend
End With
Set oRng = Nothing
Next 'i
End Sub
Dim varUbyteNormal As Variant
varUbyteNormal = Array("uword", "ubyte", "bool", "sword", "const", "ulong", "static")
Dim i As Long
For i = LBound(varUbyteNormal) To UBound(varUbyteNormal)
With ActiveDocument.Range.Find
.ClearFormatting
.ClearAllFuzzyOptions
With .Font
.Name = "Times New Roman"
.Bold = False
.Size = 10
End With
.Text = varUbyteNormal(i)
With .Replacement
.ClearFormatting
.Style = "variable normal"
End With
.Execute Replace:=wdReplaceAll
End With
Next
Related
I am trying to select all pages of a document except the 3 last ones. My final goal is to apply a style to text who have a specific font name and a specific font size. I am receiving an error message when running the code below about my 3rd code line : "object doesn't support this property or method". Any idea what this is about? Thanks!
Sub aHeadlines()
Dim V As Integer
Dim Z As Integer
V = ActiveDocument.Information(wdNumberOfPagesInDocument)
Z = 3
Dim rgePages As Range
Selection.GoTo What:=wdGoToPage, Which:=wdGoToAbsolute, Count:=1
Set rgePages = Selection.Range
Selection.GoTo What:=wdGoToPage, Which:=wdGoToAbsolute, Count:=V - Z
rgePages.End = Selection.Bookmarks("\Page").Range.End
rgePages.Select
With Selection.Find
.ClearFormatting
.Text = ""
.Font.Size = 10
.Font.Name = "Arial"
.Font.Bold = True
With .Replacement
.ClearFormatting
.Text = ""
.Style = ActiveDocument.Styles("Heading 1")
End With
.Execute Replace:=wdReplaceAll
End With
End Sub
Way simpler:
Sub Demo()
Application.ScreenUpdating = False
With ActiveDocument
With .Range(0, .Range.GoTo(What:=wdGoToPage, Which:=wdGoToAbsolute, _
Count:=.ComputeStatistics(wdStatisticPages) - 2).End - 1).Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = ""
.Replacement.Text = ""
.Font.Size = 10
.Font.Name = "Arial"
.Font.Bold = True
.Replacement.Style = wdStyleHeading1
.Execute Replace:=wdReplaceAll
End With
End With
Application.ScreenUpdating = True
End Sub
Information is a property of the Range object, not Document.
V = ActiveDocument.Range.Information(wdNumberOfPagesInDocument)
NOTE:
It is rarely necessary to select anything when working with VBA. Using the Selection object slows down your code as the cursor moves with each change of the selection which means the screen has to be redrawn each time. Instead of Selection use the appropriate object for what you are trying to do, e.g. Range, Table, Shape, etc.
Your code can be rewritten using Range as below:
Sub aHeadlines()
Dim V As Integer
Dim Z As Integer
V = ActiveDocument.Range.Information(wdNumberOfPagesInDocument)
Z = 3
Dim rgePages As Range
Set rgePages = ActiveDocument.GoTo(What:=wdGoToPage, Which:=wdGoToAbsolute, Count:=V - Z)
rgePages.End = rgePages.Bookmarks("\Page").Range.End
rgePages.Start = ActiveDocument.Range.Start
With rgePages.Find
.ClearFormatting
.Text = ""
.Font.Size = 10
.Font.Name = "Arial"
.Font.Bold = True
.Wrap = wdFindStop
With .Replacement
.ClearFormatting
.Text = ""
.Style = ActiveDocument.Styles("Heading 1")
End With
.Execute Replace:=wdReplaceAll
End With
End Sub
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 have the fantastic macro below which
Searches for words (listed in an excel file)
Copies each instance
Pastes into a new word document together with it's location from the original document
This has been created and amended by various people and I am truly greatful!!. One thing that I was wondering if possible is:
If in the word document which you're searching there are tables, can you make the macro to ignore tables? or would it be better to say 'If the word is found and is in a table ignore this instance and proceed searching te document again'
The latter would have more unnecessary iterations in my opinion.
I had managed to find the code:
Sub NonTableParagraphs()
Dim rng() As Range
Dim t As Integer
Dim tbl As Table
Dim para As Paragraph
Dim r As Integer
ReDim Preserve rng(t)
Set rng(t) = ActiveDocument.Range
For Each tbl In ActiveDocument.Tables
rng(t).End = tbl.Range.Start
t = t + 1
ReDim Preserve rng(t)
Set rng(t) = ActiveDocument.Range
rng(t).Start = tbl.Range.End
Next tbl
rng(t).End = ActiveDocument.Range.End
For r = 0 To t
For Each para In rng(r).Paragraphs
'do processing
Next para
Next r
End Sub
and had tried to insert NonTableParagraphs in the original macro, so it would run a sub routine, but I couldn't get it to work.
It looks like I should be trying to use ActiveDocument.Tables and somehow stating if ActiveDocument.Tables found, skip the rest of the lines in macro & then return to searching after the table but I can't seem to get it to work.
I'll see if I can search for that
Many thanks!!!
Sub CopyKeywordPlusContext()
'Modified 3-10-2015 TW
'Modified 2-17-2015 GKM
'Makro created on 22.01.2013
Dim oDoc As Document, oDocRecord As Document
Dim strSearch As String, arrSearch
Dim lngCharTrailing As Long, lngCharLeading As Long, lngIndex As Long, lngCount As Long
Dim lngPgNum, lngLineNum As Integer
Dim oRng As Word.Range, oRngSpan As Word.Range
Dim bFound As Boolean
Dim oTbl As Word.Table
strSearch = vbNullString
Dim xl As Object
Set xl = GetObject(, "Excel.Application")
arrSearch = xl.transpose(xl.activesheet.Range("A1:A221").Value)
lngCharLeading = 20
lngCharTrailing = 20
Set oDoc = ActiveDocument
For lngIndex = 1 To UBound(arrSearch)
ResetFRParams
bFound = False
lngCount = 0
Set oRng = oDoc.Range
With oRng.Find
.Text = LCase(arrSearch(lngIndex))
While .Execute
bFound = True
If oDocRecord Is Nothing Then
Set oDocRecord = Documents.Add
Set oTbl = oDocRecord.Tables.Add(oDocRecord.Range, 1, 2)
End If
lngCount = lngCount + 1
If lngCount = 1 Then
oTbl.Rows.Add
With oTbl.Rows.Last.Previous
.Cells.Merge
With .Cells(1).Range
.Text = "Search results for """ & arrSearch(lngIndex) & """ + context in " & """" & oDoc.Name & """"
.Font.Bold = True
End With
End With
End If
Set oRngSpan = oRng.Duplicate
oRngSpan.Select
lngPgNum = Selection.Information(wdActiveEndPageNumber)
lngLineNum = Selection.Information(wdFirstCharacterLineNumber)
With oRngSpan
.MoveStart wdCharacter, -lngCharLeading
.MoveEnd wdCharacter, lngCharTrailing
Do While oRngSpan.Characters.First = vbCr
oRngSpan.MoveStart wdCharacter, -1
Loop
Do While oRngSpan.Characters.Last = vbCr
oRngSpan.MoveEnd wdCharacter, 1
If oRngSpan.End = oDoc.Range.End Then
oRngSpan.End = oRngSpan.End - 1
Exit Do
End If
Loop
End With
oTbl.Rows.Last.Range.Cells(1).Range.Text = Trim(oRngSpan.Text)
oTbl.Rows.Last.Range.Cells(2).Range.Text = "Page: " & lngPgNum & " Line: " & lngLineNum
oTbl.Rows.Add
Wend
End With
If bFound Then
ResetFRParams
With oDocRecord.Range.Find
.Text = LCase(arrSearch(lngIndex))
.Replacement.Text = "^&"
.Replacement.Highlight = True
.Format = True
.Execute Replace:=wdReplaceAll
End With
End If
Next lngIndex
oTbl.Rows.Last.Delete
End Sub
Sub ResetFRParams()
With Selection.Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = ""
.Replacement.Text = ""
.Replacement.Highlight = False
.Forward = True
.Wrap = wdFindStop
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
.Execute
End With
lbl_Exit:
Exit Sub
End Sub
Instead of trying to debug/edit your code look at this and decide for yourself where to insert it.
Sub FindText()
Dim doc As Word.Document, rng As Word.Range
Set doc = Word.ActiveDocument
Set rng = doc.Content
With rng.Find
.ClearFormatting
.Format = False
.Forward = True
.Text = "Now is"
.Wrap = wdFindStop
.Execute
Do While .Found
If rng.Information(Word.WdInformation.wdWithInTable) Then
'do nothing
rng.Collapse Word.WdCollapseDirection.wdCollapseEnd
Else
rng.Text = "Now is not"
rng.Collapse Word.WdCollapseDirection.wdCollapseEnd
End If
.Execute
Loop
End With
End Sub
Problem:
We have certain branding formatting for our product names, but manually changing the colour and font style in every email across the company is time consuming.
Solution:
I am trying to build a Macro VBA code to instantly find these words and change the formatting.
The code needs to find a word that starts with the string "abc" and then reformats the entire word to bold and then changes the colour of the "abc" string to the correct brand's colour corresponding to the letters following the full word/product. Once it has been bolded, I don't want clicking the button again to increase the font size, so an "if bolded do nothing" is required
e.g. any word with "abctelephone" needs to be bolded and the abc changed to the corresponding brand's colour. (abctelephone with the abc in blue)
I have this scenario working in Word 2013, and I have an example code set below that I have tried to modify from the existing to replicate this functionality in an Outlook email by referencing Microsoft Word 15.0 Object Library in the Visual Basic References Tool.
Any pointers?
Sub Branding()
Dim insp As Outlook.Inspector
Dim myObject As Object
Dim msg As Outlook.MailItem
Dim myDoc As Word.Document
Dim mySelection As Word.Selection
Dim strItem As String
Dim strGreeting As String
Dim StrTxt As String, Rng As Range
Dim tempFont As String
Dim tempColour As String
Dim tempBold As String
StrTxt = "abc"
Set insp = Application.ActiveInspector
Set myObject = insp.CurrentItem
'The active inspector is displaying a mail item.
If myObject.MessageClass = "IPM.Note" And _
insp.IsWordMail = True Then
Set msg = insp.CurrentItem
'Grab the body of the message using a Word Document object.
Set myDoc = insp.WordEditor
Set mySelection = myDoc.Application.Selection
Set hed = msg.GetInspector.WordEditor
Set appWord = hed.Application
Set appRng = appWord.Selection
With mySelection.Range
With mySelection.Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = "<" & StrTxt & "*>"
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindStop
.Format = False
.MatchWildcards = True
.MatchCase = False
.Execute
End With
Do While .Find.Found
If .Font.Name <> "Arial" Then
tempFont = .Duplicate.Font.Name
tempColour = .Duplicate.Font.Color
tempBold = .Duplicate.Font.Bold
With .Duplicate
.Font.Size = .Font.Size + 2
.Font.Name = "Zrnic"
.Font.Bold = True
If .Text <> "" Then
Select Case Split(.Text, StrTxt)(1)
Case "telephone"
.End = .Start + Len(StrTxt)
.Font.Color = RGB(0, 122, 135)
Case "handset"
.End = .Start + Len(StrTxt)
.Font.Color = RGB(0, 122, 135)
Case "speaker"
.End = .Start + Len(StrTxt)
.Font.Color = RGB(0, 122, 135)
End Select
End If
End With
End If
mySelection.Find.Execute
Loop
End With
End If
End Sub
Thought I would post my final code here that updates the changes on the fly to work in the Outlook draft email.
This could be modified for your own use case.
Paste into your ThisOutlookSession
You need to add the Word Reference library.
Function GetCurrentItem() As MailItem
Dim objApp As Outlook.Application
Set objApp = Application
On Error Resume Next
Select Case TypeName(objApp.ActiveWindow)
Case "Explorer"
Set GetCurrentItem = objApp.ActiveExplorer.Selection.Item(1)
Case "Inspector"
Set GetCurrentItem = objApp.ActiveInspector.CurrentItem
End Select
Set objeApp = Nothing
End Function
Sub test()
Dim doc As Document
Dim myInspactor As Outlook.Inspector
Dim CurrMsg As Outlook.MailItem
Set CurrMsg = GetCurrentItem()
Set myInspector = CurrMsg.GetInspector
Set doc = myInspector.WordEditor
ABCBranding doc
End Sub
Sub ABCBranding(doc As Document)
Dim StrTxt As String, Rng As Range
Dim tempFont As String
Dim tempColour As String
Dim tempBold As String
StrTxt = "abc"
With doc.Range
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = "<" & StrTxt & "*>"
.Replacement.Text = ""
.forward = True
.Wrap = wdFindStop
.Format = False
.MatchWildcards = True
.MatchCase = False
.Execute
End With
Do While .Find.Found
If .Font.Name <> "Verdana" Then
tempFont = .Duplicate.Font.Name
tempColour = .Duplicate.Font.Color
tempBold = .Duplicate.Font.Bold
With .Duplicate
.Font.Name = "Arial"
.Font.Bold = True
Select Case Split(.Text, StrTxt)(1)
Case "telephone"
.End = .Start + Len(StrTxt)
.Font.Color = RGB(0, 222, 111)
Case "handset"
.End = .Start + Len(StrTxt)
.Font.Color = RGB(50, 200, 100)
Case "speaker"
.End = .Start + Len(StrTxt)
.Font.Color = RGB(43, 101, 412)
End Select
End With
End If
.Collapse wdCollapseEnd
.Find.Execute
Loop
End With
End Sub
I am trying to format text of multiple words. So far, the code below will only allow me to format the font of one word. What do I need to add / delete in order to have as many words as I input be formatted?
Cheers!
Sub FnFindAndFormat()
Dim objWord
Dim objDoc
Dim intParaCount
Dim objParagraph
Set objWord = CreateObject("Word.Application")
Set objDoc = objWord.Documents.Open("C:\USERPATH")
objWord.Visible = True
intParaCount = objDoc.Paragraphs.Count
Set objParagraph = objDoc.Paragraphs(1).range
objParagraph.Find.Text = "deal"
Do
objParagraph.Find.Execute
If objParagraph.Find.Found Then
objParagraph.Font.Name = "Times New Roman"
objParagraph.Font.Size = 20
objParagraph.Font.Bold = True
objParagraph.Font.Color = RGB(200, 200, 0)
End If
Loop While objParagraph.Find.Found
End Sub
Let's say your word document looks like this
Since I am not sure whether you are doing this from Word-VBA or from some other application like say Excel-VBA so I am including both methods.
Now if you are doing this from Word-VBA then you do not need to LateBind with it. Use this simple code.
Option Explicit
Sub Sample()
Dim oDoc As Document
Dim MyAr() As String, strToFind As String
Dim i As Long
'~~> This holds your search words
strToFind = "deal,contract, sign, award"
'~~> Create an array of text to be found
MyAr = Split(strToFind, ",")
'~~> Open the relevant word document
Set oDoc = Documents.Open("C:\Sample.docx")
'~~> Loop through the array to get the seacrh text
For i = LBound(MyAr) To UBound(MyAr)
With Selection.Find
.ClearFormatting
.Text = MyAr(i)
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindContinue
.Execute
'~~> Change the attributes
Do Until .Found = False
With Selection.Font
.Name = "Times New Roman"
.Size = 20
.Bold = True
.Color = RGB(200, 200, 0)
End With
Selection.Find.Execute
Loop
End With
Next i
End Sub
However if you are doing from say Excel-VBA then use this
Const wdFindContinue = 1
Sub FnFindAndFormat()
Dim objWord As Object, objDoc As Object, Rng As Object
Dim MyAr() As String, strToFind As String
Dim i As Long
'~~> This holds your search words
strToFind = "deal,contract, sign, award"
'~~> Create an array of text to be found
MyAr = Split(strToFind, ",")
Set objWord = CreateObject("Word.Application")
'~~> Open the relevant word document
Set objDoc = objWord.Documents.Open("C:\Sample.docx")
objWord.Visible = True
Set Rng = objWord.Selection
'~~> Loop through the array to get the seacrh text
For i = LBound(MyAr) To UBound(MyAr)
With Rng.Find
.ClearFormatting
.Text = MyAr(i)
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindContinue
.Execute
Set Rng = objWord.Selection
'~~> Change the attributes
Do Until .Found = False
With Rng.Font
.Name = "Times New Roman"
.Size = 20
.Bold = True
.Color = RGB(200, 200, 0)
End With
Rng.Find.Execute
Loop
End With
Next i
End Sub
OUTPUT
Works like a charm for me:
Public Sub Find_some_text()
'setting objects
Dim objWord
Dim objDoc
Dim objSelection
Set objWord = CreateObject("Word.Application")
Set objDoc = objWord.Documents.Open("H:\Test.docx")
'set visibility
objWord.Visible = True
'set array of words to format
words_list = Array("Findme_1", "Findme_2", "etc")
'formatting text
For Each w In words_list
Set Frange = objDoc.Range
Frange.Find.Text = w
Do
Frange.Find.Execute
If Frange.Find.Found Then
Frange.Font.Name = "Times New Roman"
Frange.Font.Size = 20
Frange.Font.Bold = True
Frange.Font.Color = RGB(200, 200, 0)
End If
Loop While Frange.Find.Found
Next
'de-set visibility
objWord.Visible = False
'saving (optional)
objDoc.Save
End Sub
This code:
For Each w In words_list
Set Frange = objDoc.Range
Frange.Find.Text = w
Do
Frange.Find.Execute
If Frange.Find.Found Then
Frange.Font.Name = "Times New Roman"
Frange.Font.Size = 20
Frange.Font.Bold = True
Frange.Font.Color = RGB(200, 200, 0)
End If
Loop While Frange.Find.Found
Next
is inefficient. Try:
With objDoc.Range.Find
.ClearFormatting
With .Replacement
.ClearFormatting
.Text = "^&"
With .Font
.Name = "Times New Roman"
.Size = 20
.Bold = True
.Color = RGB(200, 200, 0)
End With
End With
.Format = True
.Forward = True
.Wrap = 1 'wdFindContinue
For Each w In words_list
.Text = w
.Execute Replace:=2 'wdReplaceAll
Next
End With