I need to use Word Macro for automatically proofreading the documents. I have an excel file, filled in with all the wrong spelling words, and after I installed the macro to Microsoft Word, it took several minutes to finish the spelling checking for just 1 page of the Word Document.
Can I use .txt to replace the excel in order to make it faster? Or what should I improve? Below please find the code for the Macro:
Attribute VB_Name = "PR"
Option Explicit
Sub PR()
Dim Path As String
Dim objExcel As Object
Dim iCount As Integer
Dim VChar As String
Dim OChar As String
Options.AutoFormatAsYouTypeReplaceQuotes = True
Path = "D:\Macro\rplPR.xlsx"
'Highlight variant characters
With ActiveDocument
.TrackRevisions = False
.ShowRevisions = False
End With
Set objExcel = CreateObject("Excel.Application")
objExcel.Workbooks.Open Path
For iCount = 2 To 2500
Selection.HomeKey Unit:=wdStory
VChar = objExcel.ActiveWorkbook.Sheets(1).Cells(iCount, 1)
If Len(VChar) = 0 Then Exit For
Selection.HomeKey Unit:=wdStory, Extend:=wdMove
With Selection.Find
.ClearFormatting
.Replacement.ClearFormatting
.Replacement.Highlight = True
.Text = VChar
.Replacement.Text = "^&"
.Execute Replace:=wdReplaceAll
End With
Next
objExcel.ActiveWorkbook.Close
objExcel.Quit
End Sub
Move these lines up to above the For statement. You are setting them 2,499 times and you only need to do it once.
.ClearFormatting
.Replacement.ClearFormatting
.Replacement.Highlight = True
.Text = VChar
.Replacement.Text = "^&"
So each dot is a function call. There are 5 needless ones done 2498 times which is 12,490 function calls.
Function calls, while essential, are slow compared to other operations as there is a lot of setup.
If you didn't use with that would be an extra 12,490 function calls as well for a total of 24,980 sloww needless function calls.
Try the following. Do note that there is necessarily some overhead involved in starting Excel (if not already running), as well as processing the workbook. Hence, even a single-page document will encounter the same overhead there as a 100-page document.
Sub BulkFindReplace()
Application.ScreenUpdating = False
Dim xlApp As Object, xlWkBk As Object, StrWkBkNm As String, StrWkSht As String
Dim iDataRow As Long, xlFList As String, xlRList As String, i As Long
StrWkBkNm = "D:\Macro\rplPR.xlsx": StrWkSht = "Sheet1"
'Start Excel
Set xlApp = CreateObject("Excel.Application")
If xlApp Is Nothing Then
MsgBox "Can't start Excel.", vbExclamation
Exit Sub
End If
On Error GoTo 0
With xlApp
'Hide our Excel session
.Visible = False
' The file is available, so open it.
Set xlWkBk = .Workbooks.Open(StrWkBkNm, False, True)
If xlWkBk Is Nothing Then
MsgBox "Cannot open:" & vbCr & StrWkBkNm, vbExclamation
.Quit: Set xlApp = Nothing: Exit Sub
End If
' Process the workbook.
With xlWkBk
With .Worksheets(StrWkSht)
' Find the last-used row in column A.
iDataRow = .Cells(.Rows.Count, 1).End(-4162).Row ' -4162 = xlUp
' Capture the F/R data.
For i = 1 To iDataRow
' Skip over empty fields to preserve the underlying cell contents.
If Trim(.Range("A" & i)) <> vbNullString Then
xlFList = xlFList & "|" & Trim(.Range("A" & i))
xlRList = xlRList & "|" & Trim(.Range("B" & i))
End If
Next
End With
.Close False
End With
.Quit
End With
' Release Excel object memory
Set xlWkBk = Nothing: Set xlApp = Nothing
'Exit if there are no data
If xlFList = "" Then Exit Sub
'Process each word from the F/R List
With ActiveDocument.Range.Find
.ClearFormatting
.Replacement.ClearFormatting
.MatchWholeWord = True
.MatchCase = False
.Wrap = wdFindContinue
For i = 1 To UBound(Split(xlFList, "|"))
.Text = Split(xlFList, "|")(i)
.Replacement.Text = Split(xlRList, "|")(i)
.Execute Replace:=wdReplaceAll
Next
End With
Application.ScreenUpdating = True
End Sub
Related
I have a VBA code that copies data from MS Word documents in a folder and pastes them into an MS Excel file. The folder contains about over 2000 MS word files. The code opens each word file in the folder and looks for two key words, lets call them "FindWord1" and "FindWord2", then copies all the data (including text) that is located between these two keywords from this word file and pastes it into a Excel worksheet. Then moves on to the next Word file in the folder.
Some of these 2000 word documents are missing the two keywords. If the code does not find the key words (either "Findword1" or "Findword2") it returns an error. So only the word documents opened before this error are copied and pasted. Is there a way to log the files names of the word documents that are missing the keywords, skip them and move on to the next file in the folder.
The code runs fine as is, but I have to manually go and remove the file from the folder for it to go to the next file which is taking a lot of time. I would appreciate any help here.
Thanks,
N
'Note: this code requires a reference to the Word object model. See under the VBE's Tools|References.
Application.ScreenUpdating = False
'Objects
Dim wdApp As New Word.Application, wdDoc As Word.Document
Dim strFolder As String, strFile As String, lRow As Long
Dim WkSht As Worksheet: Set WkSht = ActiveSheet
'Folder Location
strFolder = "C:\Users\Folder\"
strFile = Dir(strFolder & "*.docx", vbNormal)
'Loop Start
While strFile <> ""
Set wdDoc = wdApp.Documents.Open(Filename:=strFolder & strFile, AddToRecentFiles:=False, ReadOnly:=True, Visible:=False)
lRow = WkSht.UsedRange.SpecialCells(xlCellTypeLastCell).Row + 1
With wdDoc
' Text you want to search
Dim FindWord1, FindWord2 As String
Dim result As String
FindWord1 = "Keyword1"
FindWord2 = "Keyword2"
'Style
mystyle = ""
'Defines selection for Word's find function
wdDoc.SelectAllEditableRanges
' Move your cursor to the start of the document
wdDoc.ActiveWindow.Selection.HomeKey unit:=wdStory
'Find Functionality in MS Word
With wdDoc.ActiveWindow.Selection.Find
.Text = FindWord1
.Replacement.Text = ""
.Forward = True
.Wrap = 1
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
If mystyle <> "" Then
.Style = mystyle
End If
If .Execute = False Then
MsgBox "'Text' not found.", vbExclamation
Exit Sub
End If
' Locate after the ending paragraph mark (beginning of the next paragraph)
' wdDoc.ActiveWindow.Selection.Collapse Direction:=wdCollapseEnd
' Starting character position of a selection
lngStart = wdDoc.ActiveWindow.Selection.End 'Set Selection.Start to include searched word
.Text = FindWord2
.Replacement.Text = ""
.Forward = True
.Wrap = 1
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
'.Style = mystyle
If .Execute = False Then
MsgBox "'Text2' not found.", vbExclamation
Exit Sub
End If
lngEnd = wdDoc.ActiveWindow.Selection.Start 'Set Selection.End to include searched word
End With
'Copy Selection
wdDoc.Range(lngStart, lngEnd).Copy
WkSht.Paste WkSht.Range("C" & lRow)
.Close SaveChanges:=False
End With
strFile = Dir()
Wend
wdApp.Quit
Set wdDoc = Nothing: Set wdApp = Nothing: Set WkSht = Nothing
Application.ScreenUpdating = True
End Sub
Please remember to declare all variables, add Option Explicit at the top of your module to help you enforce this.
You might know this already but Dim FindWord1, FindWord2 As String will declare FindWord1 as Variant, you have to declare the variable type for each variable one by one i.e. Dim FindWord1 As String, FindWord2 As String.
What is mysetyle for? It's not being used but I have left it there anyway, please delete if there is no use for it.
Try below code, if the Word document does not contain both keywords then it will prompt a MsgBox and Debug.Print to the immediate window, modify to your needs:
Private Sub Test()
'Note: this code requires a reference to the Word object model. See under the VBE's Tools|References.
Application.ScreenUpdating = False
'Objects
Dim wdApp As Word.Application
Dim wdDoc As Word.Document
Dim lRow As Long
Dim WkSht As Worksheet
Set WkSht = ActiveSheet
Const colPaste As Long = 3 'Column C
'Search String
Const FindWord1 As String = "Keyword1"
Const FindWord2 As String = "Keyword2"
'Folder Location
'Const strFolder As String = "C:\Users\Folder\"
Dim strFile As String
strFile = Dir(strFolder & "*.docx", vbNormal)
'Loop Start
While strFile <> vbNullString
If wdApp Is Nothing Then Set wdApp = New Word.Application
Set wdDoc = wdApp.Documents.Open(Filename:=strFolder & strFile, AddToRecentFiles:=False, ReadOnly:=True, Visible:=False)
lRow = WkSht.UsedRange.SpecialCells(xlCellTypeLastCell).Row + 1
'Style
mystyle = vbNullString
Dim firstRng As Word.Range
Set firstRng = wdDoc.Range.Duplicate
'Find Functionality in MS Word
With firstRng.Find
.Text = FindWord1
.Replacement.Text = ""
.Forward = True
.Wrap = 1
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
.Execute
End With
If firstRng.Find.Found Then
Dim secondRng As Word.Range
Set secondRng = wdDoc.Range(firstRng.End, wdDoc.Range.End).Duplicate
With secondRng.Find
.Text = FindWord2
.Replacement.Text = ""
.Forward = True
.Wrap = 1
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
.Execute
End With
If secondRng.Find.Found Then
'Found both keywords, copy to worksheet
Dim copyRng As Word.Range
Set copyRng = wdDoc.Range(firstRng.Start, secondRng.End).Duplicate
copyRng.Copy
'WkSht.Cells(lRow, colPaste).Paste
WkSht.Paste WkSht.Range("C" & lRow)
Else
'Error - second word not found~ abort and move on to next file
MsgBox "Second word not found" & vbNewLine & _
strFolder & strFile
Debug.Print "Second word not found: " & strFolder & strFile
End If
Else
'Error - first word not found~ abort and move on to next file
MsgBox "First word not found" & vbNewLine & _
strFolder & strFile
Debug.Print "First word not found: " & strFolder & strFile
End If
Set firstRng = Nothing
Set secondRng = Nothing
Set copyRng = Nothing
wdDoc.Close 0
strFile = Dir()
Wend
wdApp.Quit
Set wdDoc = Nothing
Set wdApp = Nothing
Set WkSht = Nothing
Application.ScreenUpdating = True
End Sub
Do you have lngStart and lngEnd defined somewhere? Maybe Dim them and assign 0 to both right after opening the next word doc, and then check if they are not equal to
0 before the copy to excel part. Don't have any considerable experience for Word VBA, sorry if not applicable.
I found the macro in this link and it works great, https://wordribbon.tips.net/T001173_Highlight_Words_from_a_Word_List.html:
It highlights words from another Word document in the current document. I need to see if it can work for phrases and not just single words. It's okay if I need to put identifying markers before and after the phase, like double brackets or something [[ ... ]], for example. Is this possible and how would it be placed in this macro?
If the list could be from an Excel document, that would be even better but not a deal breaker.
Examples are:
Tony the Tiger (but only when the macro finds that entire phrase. As it works now, it would find all instances of all three words independently and the 'the' would of course be problematic. Another one would be '17th c.' In this case, it finds every c and every dot as well. It would be ideal to find only the entire phrase.
The code in the link you posted is very inefficient. For a way more efficient approach, see:
https://www.msofficeforums.com/word-vba/23196-need-help-creating-macro.html
A simple solution that doesn't require another file is:
Sub BulkHighlighter()
Application.ScreenUpdating = False
Dim i As Long, StrFnd As String, HiLt As Long
HiLt = Options.DefaultHighlightColorIndex
Options.DefaultHighlightColorIndex = wdBrightGreen
StrFnd = InputBox("Insert your 'Find' terms with | delimiters, for example:" & vbCr & "the quick brown fox|jumped over|the lazy dog")
With ActiveDocument.Range.Find
.ClearFormatting
.Replacement.ClearFormatting
.MatchWholeWord = True
.MatchCase = False
.Replacement.Highlight = True
.Replacement.Text = "^&"
For i = 0 To UBound(Split(StrFnd, "|"))
.Text = Split(StrFnd, "|")(i)
.Execute Replace:=wdReplaceAll
Next
End With
Options.DefaultHighlightColorIndex = HiLt
Application.ScreenUpdating = True
End Sub
Alternatively, if the list of strings to be highlighted is fixed:
Sub BulkHighlighter()
Application.ScreenUpdating = False
Dim i As Long, StrFnd As String, HiLt As Long
HiLt = Options.DefaultHighlightColorIndex
Options.DefaultHighlightColorIndex = wdBrightGreen
StrFnd = "the quick brown fox|jumped over|the lazy dog"
With ActiveDocument.Range.Find
.ClearFormatting
.Replacement.ClearFormatting
.MatchWholeWord = True
.MatchCase = False
.Replacement.Highlight = True
.Replacement.Text = "^&"
For i = 0 To UBound(Split(StrFnd, "|"))
.Text = Split(StrFnd, "|")(i)
.Execute Replace:=wdReplaceAll
Next
End With
Options.DefaultHighlightColorIndex = HiLt
Application.ScreenUpdating = True
End Sub
If you're wedded to using an Excel file, try:
Sub BulkHighlighter()
Application.ScreenUpdating = False
Dim xlApp As Object, xlWkBk As Object, StrWkBkNm As String
Dim StrWkSht As String, xlFList As String, i As Long
'Identify the WorkBook and WorkSheet
StrWkBkNm = "C:\Users\" & Environ("Username") & "\Documents\BulkFindReplace.xlsx"
StrWkSht = "Sheet1"
On Error Resume Next
'Start Excel
Set xlApp = CreateObject("Excel.Application")
If xlApp Is Nothing Then
MsgBox "Can't start Excel.", vbExclamation
Exit Sub
End If
On Error GoTo 0
With xlApp
'Hide our Excel session
.Visible = False
' The file is available, so open it.
Set xlWkBk = .Workbooks.Open(StrWkBkNm, False, True)
If xlWkBk Is Nothing Then
MsgBox "Cannot open:" & vbCr & StrWkBkNm, vbExclamation
.Quit: Set xlApp = Nothing: Exit Sub
End If
' Process the workbook.
With xlWkBk
With .Worksheets(StrWkSht)
' Capture the F/R data.
For i = 1 To .Cells(.Rows.Count, 1).End(-4162).Row ' -4162 = xlUp
' Skip over empty fields to preserve the underlying cell contents.
If Trim(.Range("A" & i)) <> vbNullString Then
xlFList = xlFList & "|" & Trim(.Range("A" & i))
End If
Next
End With
.Close False
End With
.Quit
End With
' Release Excel object memory
Set xlWkBk = Nothing: Set xlApp = Nothing
'Exit if there are no data
If xlFList = "" Then Exit Sub
'Process each word from the F/R List
With ActiveDocument.Range.Find
.ClearFormatting
.Replacement.ClearFormatting
.MatchWholeWord = True
.MatchCase = True
.Wrap = wdFindContinue
.Replacement.Text = "^&"
For i = 1 To UBound(Split(xlFList, "|"))
.Text = Split(xlFList, "|")(i)
.Execute Replace:=wdReplaceAll
Next
End With
Application.ScreenUpdating = True
End Sub
For processing multiple documents in the same folder using an Excel workbook, see:
https://www.msofficeforums.com/70404-post4.html
Note that the code in this last link shows how to process content in headers, footers, etc. also.
This is my first post here and I'm very, very new to vba.
I have an Excel worksheet that I am using to assist in drafting several Word documents. I would like to program a command in Excel that if a specific cell has a specific value, it will delete a particular paragraph in a Word document. Specifically, I want to do something like the following:
if activesheet.range("I99")="1" then
'code to delete specific paragraph in Word document
elseif activesheet.range("I99")="2" then
'code to delete different paragraph in Word document
elseif activesheet.range("I99")="3" then
'code to delete different paragraph in Word document
end if
The following generic code (which I found on this site) in Word does what I want it to do in Word, but I can't get it to work in Excel:
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
I want to do it this way so that I can edit my Word document without having to edit the vba code. Any help would be greatly appreciated!
Mark
Set a reference to Word (early binding) (check this article)
Read the code's comments and adjust it to fit your needs
' Set a reference to Word Library
Public Sub DeleteInWord()
' Set reference to worksheet
Dim sourceSheet As Worksheet
Set sourceSheet = ThisWorkbook.Worksheets("MySheetName")
' Define word document path
Dim wordDocPath As String
wordDocPath = "C:\Temp"
' Define word document name (include extension)
Dim wordDocName As String
wordDocName = "test.docx"
' Define start word to find in word document
Dim startWord As String
' Define end word to find in word document
Dim endWord As String
' Select the case when value in range I99 is X
Select Case sourceSheet.Range("I99").Value
Case 1
'code to delete specific paragraph in Word document
startWord = "StartWordValue1"
endWord = "EndWordValue1"
Case 2
'code to delete different paragraph in Word document
startWord = "StartWordValue2"
endWord = "EndWordValue2"
Case 3
'code to delete different paragraph in Word document
startWord = "StartWordValue3"
endWord = "EndWordValue3"
End Select
' Call delete paragraph procedure
delParagrInWordByStartEndWord wordDocPath, wordDocName, startWord, endWord
End Sub
Private Sub delParagrInWordByStartEndWord(ByVal wordDocPath As String, ByVal wordDocName As String, ByVal startWord As String, ByVal endWord As String)
' Turn off stuff
Application.ScreenUpdating = False
Application.DisplayAlerts = False
' Set a reference to word
Dim wordApp As Word.Application
Set wordApp = createWordObject(True)
' Fix document path if missing last \
If Right(wordDocPath, 1) <> "\" Then wordDocPath = wordDocPath & "\"
' Build document full path
Dim wordDocFullPath As String
wordDocFullPath = wordDocPath & wordDocName
' Open word document
Dim wordDoc As Word.Document
If Not wordFileIsOpen(wordDocFullPath) Then
Set wordDoc = wordApp.Documents.Open(wordDocFullPath)
Else
Set wordDoc = wordApp.Documents(wordDocName)
End If
'Setting up the Ranges
Dim find1stRange As Word.Range
Set find1stRange = wordDoc.Range
Dim findEndRange As Word.Range
Set findEndRange = wordDoc.Range
Dim delRange As Word.Range
Set delRange = wordDoc.Range
'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
Dim delStartRange As Word.Range
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 = wordDoc.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
Dim delEndRange As Word.Range
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
' Credits: https://stackoverflow.com/a/47162311/1521579
Private Function createWordObject(Optional bVisible As Boolean = True) As Object
Dim tempWordObject As Object
On Error Resume Next
Set tempWordObject = GetObject(, "Word.Application")
If Err.Number <> 0 Then
Err.Clear
On Error GoTo CleanFail
Set tempWordObject = CreateObject("Word.Application")
End If
tempWordObject.Visible = bVisible
Set createWordObject = tempWordObject
On Error GoTo 0
Exit Function
CleanFail:
Select Case Err.Number
Case Else
MsgBox "Error " & Err.Number & vbCr & _
" (" & Err.Description & ") in procedure CreateWord."
Err.Clear
End Select
End Function
' Credits: https://stackoverflow.com/a/54040283/1521579
Private Function wordFileIsOpen(wordDocFullPath As String) As Boolean
Dim ff As Long
On Error Resume Next
ff = FreeFile()
Open wordDocFullPath For Input Lock Read As #ff
Close ff
wordFileIsOpen = (Err.Number <> 0)
On Error GoTo 0
End Function
I am trying to excecute a VBA macro from excel to remove a row in a word document if a string is present.
For i = startItem To endItem
Dim msWord As Object
Set msWord = CreateObject("Word.Application")
With msWord
.Visible = TRUE
.Documents.Open getSetting("PTC TEMPLATE") 'path of the template in msword format
.Activate
'Remove TEST ROW
'LOOP TEST TO REMOVE
Dim DirArray As Variant
DirArray = ThisWorkbook.Sheets("valveList").ListObjects("valveList").HeaderRowRange.value
For Each element In DirArray
If element Like "*TEST*" Then
Debug.Print element & "--> " & Range("valveList[" & element & "]")(i).value
If Range("valveList[" & element & "]")(i).value = "NO" Then
.ActiveDocument.Select
With .Selection.Range.Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = Range("valveList[" & element & "]")(i).value 'Find all strings in col A
.Forward = TRUE
.Wrap = wdFindStop
.MatchCase = FALSE
.MatchWholeWord = FALSE
.Execute
If .Found = TRUE Then
.Selection.Rows.Delete
End If
End With
End If
End If
Next element
'End REMOVE TEST ROW
Here I have the problem that I dont know how to refer to the found string and delete the row of the table the string belongs to.
I'm not very familiar with VBA, if someone can revise my code and explain how to solve this problem I'll be thankful
There are numerous problems with your code, including repeatedly starting Word and opening a new copy of the document you're modifying, employing Word constants with late binding, and the use of unqualified Range references. Try something along the lines of:
Sub Demo()
Dim msWord As Object, wdDoc As Object, xlSht As Worksheet, DirArray As Variant
Set xlSht = ThisWorkbook.Sheets("valveList")
DirArray = xlSht.ListObjects("valveList").HeaderRowRange.Value
Set msWord = CreateObject("Word.Application")
With msWord
.Visible = True
.ScreenUpdating = False
Set wdDoc = .Documents.Open(GetSetting("PTC TEMPLATE")) 'path of the template in msword format
For i = startItem To endItem
For Each element In DirArray
If element Like "*TEST*" Then
If xlSht.Range("valveList[" & element & "]")(i).Value = "NO" Then
With wdDoc.Range
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = xlSht.Range("valveList[" & element & "]")(i).Text 'Find all strings in col A
.Forward = True
.Wrap = 0 'wdFindStop
.MatchCase = False
.MatchWholeWord = False
End With
Do While .Find.Execute
If .Information(12) = True Then 'wdWithInTable
.Rows(1).Delete
End If
.Collapse 0 'wdCollapseEnd
Loop
End With
End If
End If
Next element
Next i
.ScreenUpdating = True
End With
End Sub
I need to have a Macro in Microsoft Word in which I search for a specified word in Excel (a name for example), but copy the text of the cell at the right (email). This is what I've done trying to solve the problem:
Dim xlApp As New Excel.Application, xlWkBk As Excel.Workbook
Dim StrWkBkNm As String, StrWkShtNm As String, LRow As Long, i As Long
StrWkBkNm = ActiveDocument.Path & "\BD.xlsx"
StrWkShtNm = "Hoja2"
With xlApp
Set xlWkBk = .Workbooks.Open(StrWkBkNm) '''''''''''''''''''
With xlWkBk
With .Worksheets(StrWkShtNm)
.Cells.Find(What:="Prueba", After:=ActiveCell, LookAt _
:=xlPart, SearchOrder:=xlByColumns, SearchDirection:=xlNext, MatchCase:= _
False, SearchFormat:=False).Activate
Selection.Copy
End With
.Close False
End With
.Quit
End With
Selection.Paste
For example, I need to search for the name "AAAA", but copy aaaa#gmail.com" in the word document. See the image for better understanding.
For a different approach, try:
Sub BulkFindReplace()
Application.ScreenUpdating = False
Dim xlApp As Object, xlWkBk As Object, StrWkBkNm As String, StrWkSht As String
Dim iDataRow As Long, xlFList As String, xlRList As String, i As Long
StrWkBkNm = ActiveDocument.Path & "\BD.xlsx"
StrWkSht = "Hoja2"
If Dir(StrWkBkNm) = "" Then
MsgBox "Cannot find the designated workbook: " & StrWkBkNm, vbExclamation
Exit Sub
End If
On Error Resume Next
'Start Excel
Set xlApp = CreateObject("Excel.Application")
If xlApp Is Nothing Then
MsgBox "Can't start Excel.", vbExclamation
Exit Sub
End If
On Error GoTo 0
With xlApp
'Hide our Excel session
.Visible = False
' The file is available, so open it.
Set xlWkBk = .Workbooks.Open(FileName:=StrWkBkNm, ReadOnly:=True, AddToMru:=False)
If xlWkBk Is Nothing Then
MsgBox "Cannot open:" & vbCr & StrWkBkNm, vbExclamation
.Quit: Set xlApp = Nothing: Exit Sub
End If
' Process the workbook.
With xlWkBk
With .Worksheets(StrWkSht)
' Find the last-used row in column A.
iDataRow = .Cells(.Rows.Count, 1).End(-4162).Row ' -4162 = xlUp
' Capture the F/R data.
For i = 1 To iDataRow
' Skip over empty fields to preserve the underlying cell contents.
If Trim(.Range("A" & i)) <> vbNullString Then
xlFList = xlFList & "|" & Trim(.Range("A" & i))
xlRList = xlRList & "|" & Trim(.Range("B" & i))
End If
Next
End With
.Close False
End With
.Quit
End With
' Release Excel object memory
Set xlWkBk = Nothing: Set xlApp = Nothing
'Exit if there are no data
If xlFList = "" Then Exit Sub
'Process each word from the F/R List
With ActiveDocument.Range.Find
.ClearFormatting
.Replacement.ClearFormatting
.MatchWholeWord = True
.MatchCase = True
.Wrap = wdFindContinue
For i = 1 To UBound(Split(xlFList, "|"))
.Text = Split(xlFList, "|")(i)
.Replacement.Text = Split(xlRList, "|")(i)
.Execute Replace:=wdReplaceAll
Next
End With
Application.ScreenUpdating = True
End Sub
With the above code, you don't need to specify the search term - the macro simply processes all potential terms in column A and replaces them with the corresponding email addresses from Column B (you can change the column references if you wish).
As coded, the email addresses are inserted as simple text strings. If you want them to be formatted as hyperlinks, insert:
'Get current autoformat options
With Options
bHead = .AutoFormatApplyHeadings
bList = .AutoFormatApplyLists
bBullet = .AutoFormatApplyBulletedLists
bOther = .AutoFormatApplyOtherParas
bQuote = .AutoFormatReplaceQuotes
bSymbol = .AutoFormatReplaceSymbols
bOrdinal = .AutoFormatReplaceOrdinals
bFraction = .AutoFormatReplaceFractions
bEmphasis = .AutoFormatReplacePlainTextEmphasis
bHLink = .AutoFormatReplaceHyperlinks
bStyle = .AutoFormatPreserveStyles
bMail = .AutoFormatPlainTextWordMail
bTag = .LabelSmartTags
End With
'Restrict autoformat options to emails
With Options
.AutoFormatApplyHeadings = False
.AutoFormatApplyLists = False
.AutoFormatApplyBulletedLists = False
.AutoFormatApplyOtherParas = False
.AutoFormatReplaceQuotes = False
.AutoFormatReplaceSymbols = False
.AutoFormatReplaceOrdinals = False
.AutoFormatReplaceFractions = False
.AutoFormatReplacePlainTextEmphasis = False
.AutoFormatReplaceHyperlinks = False
.AutoFormatPreserveStyles = False
.AutoFormatPlainTextWordMail = True
.LabelSmartTags = False
End With
after:
If xlFList = "" Then Exit Sub
and insert:
'Restore the original autoformat options
With Options
.AutoFormatApplyHeadings = bHead
.AutoFormatApplyLists = bList
.AutoFormatApplyBulletedLists = bBullet
.AutoFormatApplyOtherParas = bOther
.AutoFormatReplaceQuotes = bQuote
.AutoFormatReplaceSymbols = bSymbol
.AutoFormatReplaceOrdinals = bOrdinal
.AutoFormatReplaceFractions = bFraction
.AutoFormatReplacePlainTextEmphasis = bEmphasis
.AutoFormatReplaceHyperlinks = bHLink
.AutoFormatPreserveStyles = bStyle
.AutoFormatPlainTextWordMail = bMail
.LabelSmartTags = bTag
End With
before:
Application.ScreenUpdating = True
Short answer: use .Offset(0, 1) to get the cell to the right
Longer answer: there is a lot of opportunity for improvement here
Consider this refactor of your code:
Sub Demo()
Dim xlApp As Excel.Application, xlWkBk As Excel.Workbook, xlWkSh As Excel.Worksheet
Dim rng As Excel.Range
Dim WkBkNm As String, WkShtNm As String
Dim WorkerColumn As Long
Dim SearchTerm As String
Set xlApp = New Excel.Application
WkBkNm = ActiveDocument.Path & "\BD.xlsx"
WkShtNm = "Hoja2"
SearchTerm = "Prueba"
WorkerColumn = 1 'Update this
With xlApp
On Error Resume Next
Set xlWkBk = .Workbooks.Open(WkBkNm)
On Error GoTo 0
If xlWkBk Is Nothing Then
' File failed to open, what now?
GoTo CleanUp
End If
On Error Resume Next
Set xlWkSh = xlWkBk.Worksheets(WkShtNm)
On Error GoTo 0
If xlWkSh Is Nothing Then
' Worksheet doesn't exist, what now?
GoTo CleanUp
End If
With xlWkSh
' you should limit the search to the Worker column
Set rng = .Columns(WorkerColumn).Find( _
What:=SearchTerm, _
After:=Excel.Cells(1, WorkerColumn), _
LookAt:=Excel.xlPart, _
SearchOrder:=Excel.xlByColumns, _
SearchDirection:=Excel.xlNext, _
MatchCase:=False, _
SearchFormat:=False)
' test for value not found
If Not rng Is Nothing Then
rng.Offset(0, 1).Copy ' offset to get next column
Word.Selection.Paste 'disambiguate
End If
End With
End With
CleanUp:
On Error Resume Next
If Not xlWkBk Is Nothing Then xlWkBk.Close False
xlApp.Quit
End Sub