I using a VBA code to batch find and replace highlighted text. The macro finds and replaces the words in the document. It works well with a few number of highlighted text on a small document (1-2 pages). However, when I use this macro on a large documents which has over a 100 pages, Microsoft word crashed and becomes unresponsive so I have to forced to quit.
The code is to help make it easy to redact information. I am replacing the highlight text which occur also in tables with XXXXX and highlighted black.
Does anyone have any tips to make the code more efficient?
Here is the code
Sub FindandReplaceHighlight()
Dim strFindColor As String
Dim strReplaceColor As String
Dim strText As String
Dim objDoc As Document
Dim objRange As Range
Application.ScreenUpdating = False
Set objDoc = ActiveDocument
strFindColor = InputBox("Specify a color (enter the value):", "Specify Highlight Color")
strReplaceColor = InputBox("Specify a new color (enter the value):", "New Highlight Color")
strText = InputBox("Specify a new text (enter the value):", "New Text")
With Selection
.HomeKey Unit:=wdStory
With Selection.Find
.Highlight = True
Do While .Execute
If Selection.Range.HighlightColorIndex = strFindColor Then
Set objRange = Selection.Range
objRange.HighlightColorIndex = strReplaceColor
objRange.Text = strText
objRange.Font.ColorIndex = wdBlack
Selection.Collapse wdCollapseEnd
End If
Loop
End With
End With
Application.ScreenUpdating = True
End Sub
Try:
Sub FindandReplaceHighlight()
Application.ScreenUpdating = False
Dim ClrFnd As Long, ClrRep As Long, strTxt As String
Const StrColors As String = vbCr & _
" 1 Black" & vbCr & _
" 2 Blue" & vbCr & _
" 3 Turquoise" & vbCr & _
" 4 Bright Green" & vbCr & _
" 5 Pink" & vbCr & _
" 6 Red" & vbCr & _
" 7 Yellow" & vbCr & _
" 8 White" & vbCr & _
" 9 Dark Blue" & vbCr & _
"10 Teal" & vbCr & _
"11 Green" & vbCr & _
"12 Violet" & vbCr & _
"13 Dark Red" & vbCr & _
"14 Dark Yellow" & vbCr & _
"15 Gray 50" & vbCr & _
"16 Gray 25%"
ClrFnd = InputBox("Specify the old color (enter the value):" & StrColors, "Specify Highlight Color")
ClrRep = InputBox("Specify the new color (enter the value):" & StrColors, "New Highlight Color")
strTxt = InputBox("Specify the new text (enter the value):", "New Text")
With ActiveDocument
With .Range
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Highlight = True
.Forward = True
.Wrap = wdFindStop
End With
Do While .Find.Execute
If .HighlightColorIndex = ClrFnd Then
.HighlightColorIndex = ClrRep
.Text = strTxt
.Font.ColorIndex = wdBlack
.Collapse wdCollapseEnd
End If
Loop
End With
End With
Application.ScreenUpdating = True
End Sub
Related
I am trying to create a word document from excel. the document has specific text that doesnt vary with some data being entered from excel sheet which is being entered by means of an array. so whenever this variable data from sheet is entered, the word document adjust the lines as per the length of this variable. I want to keep the non variable part of my text to be sticking to its specific position regardeless of length of varying data being imported from sheets. Iam also struggling with adjusting the sentence length to match with the paper width. can you pls help
Sub ReminderWordDoc(strValue As String)
Dim wdApp As Word.Application
Set wdApp = CreateObject("Word.Application")
With wdApp
.Visible = True
.Activate
.Documents.Add
Dim objVar As Variant
objVar = Split(strValue, "~")
With .Selection
.ParagraphFormat.Alignment = wdAlignParagraphRight
.BoldRun 'Switch Bold on
.Font.Size = 12
.Font.Name = Arial
.Font.Underline = wdUnderlineSingle
.TypeText "IN LIEU OF MSG FORM"
.TypeParagraph 'Enter a new line
.ParagraphFormat.Alignment = wdAlignParagraphLeft
.TypeText "PRIORITY"
.BoldRun 'Switch Bold off
.TypeParagraph
.TypeText "FROM: HQ FORT DTG : 02" & vbCrLf
.TypeText "TO: " + UCase(objVar(1)) + " UNCLAS" & vbCrLf
.TypeText "INFO: " + UCase(objVar(2)) + " " + UCase(objVar(1)) & vbCrLf
.TypeText "--------------------------------------------------------------------------------------------------------------------" & vbCrLf
.TypeText " REMINDER NO 1 (.) COMPLAINT IN R/O " + UCase(objVar(3)) + " " + UCase(objVar(4)) + " " + UCase(objVar(2)) + _
"(.) REF OUR LETTER NO " + UCase(objVar(0)) + _
" DT ___________(___) COMMA _______(____) COMMA _______(____)(.) 'R' OF AS ASKED VIDE OUR LETTER UNDER REF IS STILL AWAITED (.) REQUEST FWD THE SAME BY _______ (___) (.) " & vbCrLf
.TypeText "--------------------------------------------------------------------------------------------------------------------" & vbCrLf
.TypeText "XYZ TELE:27676455 SR MGR" & vbCrLf & vbCrLf & vbCrLf & vbCrLf & vbCrLf
.TypeText "CASE NO: " + UCase(objVar(0)) + " EXEC " & vbCrLf
.TypeText "DATED: " + UCase(Date) + " TOR____H" & vbCrLf
End With
End With
End Sub
Using tables is one way.
Sub ReminderWordDoc(strValue As String)
Dim wdApp As Word.Application
Set wdApp = CreateObject("Word.Application")
Dim wdDoc As Word.Document
With wdApp
.Visible = True
.Activate
End With
Set wdDoc = wdApp.Documents.Add
Dim objVar As Variant
objVar = Split(strValue, "~")
With wdApp.Selection
.ParagraphFormat.Alignment = wdAlignParagraphRight
.BoldRun 'Switch Bold on
.Font.Size = 12
.Font.Name = Arial
.Font.Underline = wdUnderlineSingle
.TypeText "IN LIEU OF MSG FORM"
.TypeParagraph 'Enter a new line
.ParagraphFormat.Alignment = wdAlignParagraphLeft
.TypeText "PRIORITY"
.BoldRun 'Switch Bold off
.TypeParagraph
End With
Dim t1 As Word.Table
Set t1 = wdDoc.Tables.Add(Range:=wdApp.Selection.Range, NumRows:=9, NumColumns:=2, _
DefaultTableBehavior:=wdWord9TableBehavior, _
AutoFitBehavior:=wdAutoFitFixed)
t1.Borders.Enable = False
w = t1.Rows(1).Cells(1).Width * 2
w1 = w * 0.75
w2 = w * 0.25
For x = 1 To 9
With t1.Rows(x)
.Cells(1).Width = w1
.Cells(2).Width = w2
End With
Next x
t1.Rows(1).Cells(1).Range.Text = "FROM: HQ FORT"
t1.Rows(1).Cells(2).Range.Text = "DTG : 02"
t1.Rows(2).Cells(1).Range.Text = "TO: " + UCase(objVar(1))
t1.Rows(2).Cells(2).Range.Text = "UNCLAS"
t1.Rows(3).Cells(1).Range.Text = "INFO: " + UCase(objVar(2))
t1.Rows(3).Cells(2).Range.Text = UCase(objVar(1))
t1.Rows(4).Cells.Merge
t1.Rows(4).Cells(1).Range.Text = String(116, "-")
t1.Rows(5).Cells.Merge
t1.Rows(5).Cells(1).Range.Text = " REMINDER NO 1 (.) COMPLAINT IN R/O " + UCase(objVar(3)) + " " + UCase(objVar(4)) + " " + UCase(objVar(2)) + _
"(.) REF OUR LETTER NO " + UCase(objVar(0)) + _
" DT ___________(___) COMMA _______(____) COMMA _______(____)(.) 'R' OF AS ASKED VIDE OUR LETTER UNDER REF IS STILL AWAITED (.) REQUEST FWD THE SAME BY _______ (___) (.) "
t1.Rows(6).Cells.Merge
t1.Rows(6).Cells(1).Range.Text = String(116, "-")
t1.Rows(7).Cells(1).Split NumRows:=1, NumColumns:=2
t1.Rows(7).Cells(1).Range.Text = "XYZ"
t1.Rows(7).Cells(2).Range.Text = "TELE:27676455"
t1.Rows(7).Cells(3).Range.Text = "SR MGR"
t1.Rows(8).Cells(1).Range.Text = "CASE NO: " + UCase(objVar(0))
t1.Rows(8).Cells(2).Range.Text = "EXEC"
t1.Rows(9).Cells(1).Range.Text = "DATED: " + UCase(Date)
t1.Rows(9).Cells(2).Range.Text = "TOR____H"
End Sub
I'm trying to search specific words in the selected/highlighted text. The result should show how much the word is used throughout the highlighted selected area.
I wrote a macro, but the total value of words shown is calculated through the entire document, not the selected part.
Sub CountWords()
'macros for counting specific words in the document
'to count the number of a specified word, this word needs to be highlighted
Dim rng As Range
Dim sWord As String
Dim i As Long
Dim sWord As String
Set rng = Selection.Range
Application.ScreenUpdating = False
sWord = InputBox( _
Prompt:="What word do you want to count?", _
Title:="Count Words", Default:="")
With rng.Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = sWord
.Forward = True
.MatchWholeWord = True
.MatchWildcards = False
.Wrap = wdFindStop
Do While .Execute
i = i + 1
Loop
End With
Select Case i
Case 2 To 4
MsgBox "word " & Chr(171) & sWord & Chr(187) & " occurred in the document " & i & " times", _
vbInformation, "word count"
Case 1
MsgBox "word " & Chr(171) & sWord & Chr(187) & " occurred in the document " & i & " times", _
vbInformation, "word count"
Case Else
MsgBox "word " & Chr(171) & sWord & Chr(187) & " occurred in the document " & i & " times", _
vbInformation, "word count"
End Select
rng.Find.Text = ""
Application.ScreenUpdating = True
End Sub
I've tried a bunch of stuff, even other peoples codes. Every one of them counts specific words throughout the entire document.
For example:
Sub Demo()
Application.ScreenUpdating = False
Dim Rng As Range, sWord As String, i As Long
sWord = InputBox(Prompt:="What word do you want to count?", Title:="Count Words", Default:="")
With Selection
Set Rng = .Range
.Collapse wdCollapseStart
With .Range
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = sWord
.Forward = True
.MatchWholeWord = True
.MatchWildcards = False
.Wrap = wdFindStop
End With
Do While .Find.Execute
If .InRange(Rng) = False Then Exit Do
i = i + 1
Loop
End With
End With
Rng.Select
MsgBox "The word " & Chr(171) & sWord & Chr(187) & " occurred " & i & " times in the selected range.", _
vbInformation, "word count"
Application.ScreenUpdating = True
End Sub
I am trying to find all of the cells with a certain text of "0.118" in column 2 of my table and do a list of commands for that row
I am also trying to take the value from column 5 of that selected text found in that row and subtract the value I put in the input box for that row.
The problem I am having is that it only changes one of my found "0.118" and not all of them in each row.
And I can't figure out how to search for the column(5) of that selected row.
Any help would be greatly appreciated.
Thank you.
Sub ConvertTo_3MM()
Dim oTable As Table
Dim stT As Long, enT As Long
Dim stS As Long, enS As Long
With Selection.Find
.Forward = True
.MatchPhrase = True
.Execute FindText:="0.118"
End With
For Each oTable In ActiveDocument.Tables
Do While Selection.Find.Execute = True
stT = oTable.Range.Start
enT = oTable.Range.End
stS = Selection.Range.Start
enS = Selection.Range.End
If stS < stT Or enS > enT Then Exit Do
Selection.Collapse wdCollapseStart
If ActiveDocument.Tables.Count >= 1 Then
With ActiveDocument.Tables(1).Cell(nRow, 2).Range
.Text = "3 MM" & vbCrLf & "-" & vbCrLf & "6 MM"
End With
End If
Selection.MoveRight Unit:=wdCell
If ActiveDocument.Tables.Count >= 1 Then
With ActiveDocument.Tables(1).Cell(nRow, 3).Range
.InsertAfter Text:=vbCrLf & "-" & vbCrLf & "SHANK"
End With
End If
Selection.MoveRight Unit:=wdCell
Selection.MoveRight Unit:=wdCell
response = InputBox("Cut Length For 3 MM")
If ActiveDocument.Tables.Count >= 1 Then
With ActiveDocument.Tables(1).Cell(nRow, 5).Range
.Text = response & vbCrLf & "-" & vbCrLf & (column(5).value - response)
End With
End If
Selection.Find.Execute Replace:=wdReplaceAll
Loop
Selection.Collapse wdCollapseEnd
Next
Application.ScreenUpdating = True
End Sub
I would be very surprised if the code in your question actually does anything as it doesn't even compile.
Your code is rather a confused mess so I'm not entirely certain that I have correctly understood what you are attempting to do, but try this:
Sub ConvertTo_3MM()
Application.ScreenUpdating = False
Dim oTable As Table
Dim response As String
For Each oTable In ActiveDocument.Tables
With oTable.Range
With .Find
.Forward = True
.MatchPhrase = True
.Text = "0.118"
.Wrap = wdFindStop
.Execute
End With
Do While .Find.Found = True
.Text = "3 MM" & vbCr & "-" & vbCr & "6 MM"
With .Rows(1)
.Cells(3).Range.InsertAfter Text:=vbCr & "-" & vbCr & "SHANK"
response = Val(InputBox("Cut Length For 3 MM"))
With .Cells(5).Range
.Text = response & vbCr & "-" & vbCr & (Val(.Text) - response)
End With
End With
.Collapse wdCollapseEnd
.Find.Execute
Loop
End With
Next
Application.ScreenUpdating = True
End Sub
Thi may not be a solution, but I do see some problems:
You do:
For Each oTable In ActiveDocument.Tables
Then you do inside that loop:
Do While Selection.Find.Execute = True
but this Find will not be limited to the table of the For Each loop.
Though harmless, inside this Do While loop you do:
If ActiveDocument.Tables.Count >= 1 Then
but of course this is true because the For Each already determined there is at least 1 table.
I suggest you lookup the documentation of Find, rethink the logic and then run it step by step in the debugger to see what the code is doing.
Try this code:
Sub ConvertTo_3MM()
Dim oTable As Table, rng As Range
Dim nRow As Long, response As String
For Each oTable In ActiveDocument.Tables
With oTable
Set rng = .Range
Do
If rng.Find.Execute("0.118") Then
If rng.Information(wdEndOfRangeColumnNumber) = 2 Then
nRow = rng.Information(wdEndOfRangeRowNumber)
.Cell(nRow, 2).Range.Text = "3 MM" & vbCrLf & "-" & vbCrLf & "6 MM"
.Cell(nRow, 3).Range.InsertAfter Text:=vbCrLf & "-" & vbCrLf & "SHANK"
response = Val(InputBox("Cut Length For 3 MM"))
.Cell(nRow, 5).Range.Text = response & _
vbCrLf & "-" & vbCrLf & (Val(.Cell(nRow, 5).Range.Text) - response)
End If
Else
Exit Do
End If
rng.Collapse wdCollapseEnd
Loop
End With
Next
Application.ScreenUpdating = True
End Sub
Before
After
I'm trying to make the "number of occurrences" either be written in red or in bolded red. Can someone please point me in the right direction. I'm new to coding. This is a word-counter, and when 2+ words are found...it displays the number of words found at the bottom of the word document.
Sub a3()
Dim Word As String
Dim wcount As Integer
Word = InputBox("Search for a word")
If (Word <= "") Then
MsgBox ("Did not enter word")
End If
If (Word > "") Then
wcount = 0
With Selection
.HomeKey Unit:=wdStory
With ActiveDocument.Content.Find
.Text = Word
Do While .Execute
wcount = wcount + 1
Selection.MoveRight
Loop
End With
MsgBox ("The word: '" & Word & "' shows up " & wcount & " times in the document")
End With
End If
If (wcount <= 2) Then
ActiveDocument.Content.InsertAfter Text:=(vbCrLf & "Number occurrences: " & wcount)
Selection.Font.ColorIndex = wdRed
ElseIf (wcount <= 3) Then
ActiveDocument.Content.InsertAfter Text:=(vbCrLf & "Number occurrences: " & wcount)
Selection.Font.ColorIndex = wdRed
Selection.Font.Bold = True
Else
ActiveDocument.Content.InsertAfter Text:=(vbCrLf & "Number occurrences: " & wcount)
Selection.Font.ColorIndex = wdBlack
Selection.Font.Bold = False
End If
End Sub
Working with Word Range objects will help with this. Think of a Range like an invisible selection, except that code can work with multiple Range objects, while there can be only one Selection.
Assign the document's content to a Range, then perform the Find and extension on that. Then the formatting can also be applied to the Range. I've altered (but not tested) the code in the question to demonstrate.
In the last part, where text is written at the end of the document, the Range object is set to the entire document, then collapsed (think of it like pressing the right-arrow key with a selection). Then the new text is assigned to the range and formatting applied. Because the range will contain only the new text, the formatting is applied to that, only.
(Additional notes: I've changed the Word variable name to sWord because "Word" could be misunderstood to mean the Word application. I've also changed the comparison to check whether sWord contains something to Len(sWord) > 0 because the "greater than """ comparison is not guaranteed.)
Sub a3()
Dim sWord As String
Dim wcount As Integer
Dim rng as Word.Range
Set rng = ActiveDocument.Content
sWord = InputBox("Search for a word")
If (sWord <= "") Then
MsgBox ("Did not enter word")
End If
If (Len(sWord) > 0) Then
wcount = 0
With Selection
.HomeKey Unit:=wdStory
With rng.Find
.Text = sWord
Do While .Execute
wcount = wcount + 1
rng.Collapse wdCollapseEnd
Loop
End With
MsgBox ("The word: '" & sWord & "' shows up " & wcount & " times in the document")
End With
End If
Set rng = ActiveDocument.Content
rng.Collapse wdCollapseEnd
If (wcount <= 2) Then
rng.Text = (vbCrLf & "Number occurrences: " & wcount)
rng.Font.ColorIndex = wdRed
ElseIf (wcount <= 3) Then
rng.Text = (vbCrLf & "Number occurrences: " & wcount)
rng.Font.ColorIndex = wdRed
rng.Font.Bold = True
Else
rng.Text = (vbCrLf & "Number occurrences: " & wcount)
rng.Font.ColorIndex = wdBlack
rng.Font.Bold = False
End If
End Sub
There are many ways to do this, some of them are based on a preference for ranges or selections and also the structure of the Find statement. Here is my preference.
Sub a3()
Dim wrd As String
Dim wcount As Integer
Dim rng As Word.Range
wrd = InputBox("Search for a word")
If wrd = vbNullString Then
MsgBox ("Did not enter word")
Exit Sub
End If
Set rng = ActiveDocument.Content
wcount = 0
With rng.Find
.ClearFormatting
.Format = False
.Forward = True
.MatchWholeWord = True
.Text = wrd
.Wrap = wdFindStop
.Execute
Do While .found
wcount = wcount + 1
rng.Collapse Word.WdCollapseDirection.wdCollapseEnd
.Execute
Loop
End With
MsgBox ("The word: " & "" & wrd & "" & " shows up " & wcount & " times in the document")
ActiveDocument.Content.InsertParagraphAfter
Set rng = ActiveDocument.Content
rng.Collapse Word.WdCollapseDirection.wdCollapseEnd
rng.Text = "Number occurrences: " & wcount
If wcount < 3 Then
rng.Font.ColorIndex = wdRed
ElseIf wcount < 4 Then
rng.Font.ColorIndex = wdRed
rng.Font.Bold = True
Else
rng.Font.ColorIndex = wdAuto
rng.Font.Bold = False
End If
End Sub
I created a Loop to find each iteration of some HTML code and return the e-mail data as a string. What we are looking for is:
'Jibberish HTML Code
<p><b><font color="#000066" size="3" face="Arial">Delivery has failed to these recipients or groups:</font></b></p>
<font color="#000000" size="2" face="Tahoma"><p>last.first#location.company.com<br>
'Jibberish HTML Code
<p><b><font color="#000066" size="3" face="Arial">Delivery has failed to these recipients or groups:</font></b></p>
<font color="#000000" size="2" face="Tahoma"><p>last.first#location.company.com<br>
'Jibberish HTML Code
<p><b><font color="#000066" size="3" face="Arial">Delivery has failed to these recipients or groups:</font></b></p>
<font color="#000000" size="2" face="Tahoma"><p>last.first#location.company.com<br>
This code will find the FIRST iteration and as of right now the Loop creates an infite loop on the first found value (doesn't move to next found value:
Sub RevisedFindIt()
' Purpose: display the text between (but not including)
' the words "Title" and "Address" if they both appear.
Dim rng1 As Range
Dim rng2 As Range
Dim strTheText As String
Set rng1 = ActiveDocument.Range
With rng1.Find
.Execute FindText:="<font color=" & Chr(34) & "#000000" & Chr(34) & " size=" & Chr(34) & "2" & Chr(34) & " face=" & Chr(34) & "Tahoma" & Chr(34) & "><p><a href=" & Chr(34) & "mailto:", Forward:=True
Do While .Found
Set rng2 = ActiveDocument.Range(rng1.End, ActiveDocument.Range.End)
If rng2.Find.Execute(FindText:=Chr(34) & ">") Then
strTheText = ActiveDocument.Range(rng1.End, rng2.Start).Text
'Debug.Print strTheText
CreateObject("Excel.Application").Run "'TestExport.xlsm'!RunIt", strTheText
End If
Loop
End With
End Sub
The data is being passed to an Excel Sub:
Public Sub RunIt(strTheText As String)
Dim LastRow As Long
Debug.Print strTheText & "Test"
LastRow = ActiveWorkbook.ActiveSheet.Range("A" & ActiveWorkbook.ActiveSheet.Rows.Count).End(xlUp).Row + 1
ActiveWorkbook.ActiveSheet.Range("A" & LastRow).Value = strTheText
End Sub
How do I get the search to skip to the next iteration in Word VBA?
Solved by changing the rng1 mid loop and refinding the data:
Sub RevisedFindIt()
' Purpose: display the text between (but not including) two strings
Dim rng1 As Range
Dim rng2 As Range
Dim strTheText As String
Set rng1 = ActiveDocument.Range
Do
With rng1.Find
.Execute FindText:="<font color=" & Chr(34) & "#000000" & Chr(34) & " size=" & Chr(34) & "2" & Chr(34) & " face=" & Chr(34) & "Tahoma" & Chr(34) & "><p><a href=" & Chr(34) & "mailto:"
If .Found Then
Set rng2 = ActiveDocument.Range(rng1.End, ActiveDocument.Range.End)
If rng2.Find.Execute(FindText:=Chr(34) & ">") Then
strTheText = ActiveDocument.Range(rng1.End, rng2.Start).Text
'Debug.Print strTheText
CreateObject("Excel.Application").Run "'TestExport.xlsm'!RunIt", strTheText
End If
Set rng1 = ActiveDocument.Range(rng2.End, ActiveDocument.Range.End)
Else
Exit Do
End If
End With
Loop
End Sub
In fact, all you need is simple:
.execute
before your only
End If
Your problem looks to be because the value of rng1.Found never changes once you're inside the Do While .Found loop. The .Found in Do While .Found refers to rng1.Found because of the With rng1.Find statement that contains it.
Sub M_snb()
sn = Split(Replace(Join(Filter(Split(LCase(ActiveDocument.Content), Chr(34)), "mailto:"), "|"), "mailto:", ""), "|")
With CreateObject("Excel.Application")
.workbooks.Add().sheets(1).Cells(1).Resize(UBound(sn) + 1) = .Application.transpose(sn)
.Visible = True
End With
End Sub