Selecting specific controls when extracting from word to excel - excel

Is it possible to select which specific form controls are extracted from word to excel?
I have a macro at the moment that works fine and extracts all the form controls into excel, onto one single row. The thing is, I need to break down the controls into 3 different sections. Each having its own sheet/tab. The form controls are text and drop down lists.
For example: Say the form has 9 questions.
1st worksheet/tab, macro will pull questions
1.
2.
3.
2nd worksheet/tab, macro will pull questions (I don't mind a separate macro)
4.
5.
6.
3rd worksheet/tab macro will pull questions(I don't mind a separate macro)
7.
8.
9.
Current macro that runs great, but brings in every single control:
Sub GetFormData()
'Note: this code requires a reference to the Word object model
Application.ScreenUpdating = False
Dim wdApp As New Word.Application, wdDoc As Word.Document, CCtrl As Word.ContentControl
Dim strFolder As String, strFile As String, WkSht As Worksheet, i As Long, j As Long
strFolder = GetFolder
If strFolder = "" Then Exit Sub
Set WkSht = ActiveSheet
i = WkSht.Cells(WkSht.Rows.Count, 1).End(xlUp).Row
strFile = Dir(strFolder & "\*.docx", vbNormal)
While strFile <> ""
i = i + 1
Set wdDoc = wdApp.Documents.Open(Filename:=strFolder & "\" & strFile, AddToRecentFiles:=False, Visible:=False)
With wdDoc
j = 0
For Each CCtrl In .ContentControls
With CCtrl
Select Case .Type
Case Is = wdContentControlCheckBox
j = j + 1
WkSht.Cells(i, j).Value = .Checked
Case wdContentControlDate, wdContentControlDropdownList, wdContentControlRichText, wdContentControlText
j = j + 1
WkSht.Cells(i, j).Value = .Range.Text
Case Else
End Select
End With
Next
.Close SaveChanges:=False
End With
strFile = Dir()
Wend
wdApp.Quit
Set wdDoc = Nothing: Set wdApp = Nothing: Set WkSht = Nothing
Application.ScreenUpdating = True
End Sub
Function GetFolder() As String
Dim oFolder As Object
GetFolder = ""
Set oFolder = CreateObject("Shell.Application").BrowseForFolder(0, "Choose a folder", 0)
If (Not oFolder Is Nothing) Then GetFolder = oFolder.Items.Item.Path
Set oFolder = Nothing
End Function
Example of what it looks like. The questions are repeated so dont mind them:

Here 's an outline to approach what you want. Basically it's all in the set up. My solution assumes that each control in your Word document has the Title field set and defined to a unique value.
My suggestion is to isolate similarly coded logic into separate functions. As an example, the SaveControlData and IsInArray.
Option Explicit
Sub example()
Dim thisSheet As Worksheet
Dim thatSheet As Worksheet
Dim theOtherSheet As Worksheet
Set thisSheet = ThisWorkbook.Sheets("Sheet1")
Set thatSheet = ThisWorkbook.Sheets("Sheet2")
Set theOtherSheet = ThisWorkbook.Sheets("Sheet3")
'--- map the control (by Title) to each worksheet
Dim thisTitles As Variant
Dim thatTitles As Variant
Dim theOtherTitles As Variant
thisTitles = Split("MyCheckbox,MyTextbox", ",")
thatTitles = Split("MyDatebox", ",")
theOtherTitles = Split("MyCheckbox,MyDatebox", ",")
Dim wdApp As Word.Application
Set wdApp = New Word.Application
Dim wdDoc As Word.Document
Set wdDoc = wdApp.Documents.Open("C:\Temp\Test text.docx")
'--- determine the starting point for data on each worksheet
Dim thisCell As Range
Dim thatCell As Range
Dim theOtherCell As Range
Set thisCell = thisSheet.Range("A1") 'calculate last row?
Set thatCell = thatSheet.Range("A1")
Set theOtherCell = theOtherSheet.Range("A1")
Dim CCtrl As Word.ContentControl
With wdDoc
For Each CCtrl In .ContentControls
'--- arranging the If statements like this means you could
' technically copy the same control value to different
' worksheets
If IsInArray(thisTitles, CCtrl.Title) Then
SaveControlData thisCell, CCtrl
thisCell.Offset(0, 1).value = CCtrl.Title
Set thisCell = thisCell.Offset(1, 0)
End If
If IsInArray(thatTitles, CCtrl.Title) Then
SaveControlData thatCell, CCtrl
thatCell.Offset(0, 1).value = CCtrl.Title
Set thatCell = thatCell.Offset(1, 0)
End If
If IsInArray(theOtherTitles, CCtrl.Title) Then
SaveControlData theOtherCell, CCtrl
theOtherCell.Offset(0, 1).value = CCtrl.Title
Set theOtherCell = theOtherCell.Offset(1, 0)
End If
Next CCtrl
End With
wdDoc.Close SaveChanges:=False
wdApp.Quit
End Sub
Private Function IsInArray(ByRef wordList As Variant, ByVal thisWord As String) As Boolean
IsInArray = False
Dim i As Long
For i = LBound(wordList, 1) To UBound(wordList, 1)
If wordList(i) = thisWord Then
IsInArray = True
Exit Function
End If
Next i
End Function
Private Sub SaveControlData(ByRef cell As Range, ByRef CCtrl As Variant)
With CCtrl
Select Case .Type
Case Is = wdContentControlCheckBox
cell.value = .Checked
Case wdContentControlDate, _
wdContentControlDropdownList, _
wdContentControlRichText, _
wdContentControlText
cell.value = .Range.Text
Case Else
End Select
End With
End Sub

Related

Open Multiple WORD FILES based on a list, perform tasks , save and close

I'd like to open a bunch of word files, from a list of file names in my excel workbook, activate the opened word files, perform a text replacement, and save the changes.
I can't make the liaison between Excel VBA and Word files.
Dim wdApp As Object, wddoc As Object
'Declare a string variable for Word document
Dim strDocName As String
On Error Resume Next
Set wdApp = CreateObject("Word.Application")
wdApp.Visible = True
strDocName = xDPathStr \ "FILENAME.docx" '(xDPathStr is the path I have defined earlier with all the word files)'
'Open Word File
wdApp.Activate
Set wddoc = wdApp.Documents(strDocName)
If wddoc Is Nothing Then Set wddoc = wdApp.Documents.Open(strDocName)
wddoc.Activate
wrdApp.Visible = True
Modify Word Files From a List in Excel
It is assumed that the file names are in column A. It will open each file and replace all occurrences of one string with another.
The focus here is on how to reference (open) Word, open files, modify them (not so much), close them with saving changes, and finally close Word only if it was initially closed.
Option Explicit
Sub VisitWord()
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Late Binding (not recommended at this stage)
' When you get familiar with how it works, switch to Late Binding:
' Dim wdApp As Object
' Dim WordWasClosed As Boolean
' On Error Resume Next ' see if Word is open
' Set wdApp = GetObject(, "Word.Application") ' attempt to create a reference to it
' On Error GoTo 0
' If wdApp Is Nothing Then ' Word is not open
' WordWasClosed = True
' Set wdApp = CreateObject("Word.Application") ' open and create a reference to it
' End If
' wdApp.Visible = True ' default is false; outcomment when done testing
' Dim wdDoc As Object
' ' etc.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Early Binding
' For this to work, in Excel, you need to create a reference to
' Tools > References > Microsoft Word 16.0 Object Library
' Use this to have the Word intellisense work for you.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Const WordFolderPath As String = "C:\Test\"
Const FINDSTRING As String = "Old String"
Const REPLACESTRING As String = "New String"
Dim wb As Workbook: Set wb = ThisWorkbook
Dim ws As Worksheet: Set ws = wb.Worksheets("Sheet1")
Dim rg As Range
Set rg = ws.Range("A2", ws.Cells(ws.Rows.Count, "A").End(xlUp))
Dim wdApp As Word.Application
Dim WordWasClosed As Boolean
On Error Resume Next ' see if Word is open
Set wdApp = Word.Application ' attempt to create a reference to it
On Error GoTo 0
If wdApp Is Nothing Then ' Word is not open
WordWasClosed = True
Set wdApp = New Word.Application ' open and create a reference to it
End If
wdApp.Visible = True ' default is false; outcomment when done testing
Dim cell As Range
Dim wdDoc As Word.Document
Dim WordFileName As String
Dim WordFilePath As String
For Each cell In rg.Cells
WordFileName = CStr(cell.Value)
If Len(WordFileName) > 0 Then
WordFilePath = WordFolderPath & WordFileName
If Len(Dir(WordFilePath)) > 0 Then ' file exists
Set wdDoc = wdApp.Documents.Open(WordFilePath)
' Here you do the damage...
wdDoc.Content.Find.Execute _
FindText:=FINDSTRING, _
ReplaceWith:=REPLACESTRING, _
Format:=True, _
Replace:=wdReplaceAll
wdDoc.Close SaveChanges:=True
End If
End If
Next cell
If WordWasClosed Then wdApp.Quit
End Sub
So this is the code i've come up with so far:
Dim wdApp As Object, wddoc As Object
'Declare a string variable for Word document
Dim strDocName As String
On Error Resume Next
Set wdApp = CreateObject("Word.Application")
wdApp.Visible = True
strDocName = xDPathStr \ "FILENAME.docx" '(xDPathStr is the path I have defined earlier with all the word files)'
'Open Word File
wdApp.Activate
Set wddoc = wdApp.Documents(strDocName)
If wddoc Is Nothing Then Set wddoc = wdApp.Documents.Open(strDocName)
wddoc.Activate
wrdApp.Visible = True
Here is some sample code that I created recently to loop through cells in Excel, which are paths to Word files. Each Word file is opened, scanned for a table (in Word), and copy/paste to Excel. See if you can start with this. Post back if you have additional questions.
Sub LoopThroughAllWordFiles()
Dim wdApp As New Word.Application, wdDoc As Word.Document
Dim oTbl As Word.Table
Dim strFolder As String, strFile As String
Dim WkSht As Worksheet
Dim cnt As Long
Dim tableCount As Long
Dim lrow As Long
Dim lastrow As Long
Dim file As String
Dim rng As Range, cell As Range
Dim objDoc As Object
Dim objWord As Object
Dim StartTime As Double
Dim SecondsElapsed As Double
StartTime = Timer
Set rng = Worksheets("Files").Range("A1:A200")
Worksheets("Word_Tables").Select
filecounter = 1
cnt = 1
Set objWord = CreateObject("Word.Application")
obj.Word.Visible = False
For Each cell In rng.SpecialCells(xlCellTypeVisible)
MyStr = Right(cell, 5)
If MyStr = ".docx" Then
mylength = Len(cell)
pos = InStrRev(cell, "\")
strFolder = Left(cell, pos)
strFile = Right(cell, mylength - pos)
Worksheets("Word_Files").Select
Set objWord = wdApp.Documents.Open(Filename:=strFolder & strFile, AddToRecentFiles:=False, ReadOnly:=True, Visible:=False)
Set sht = ThisWorkbook.Worksheets("Word_Files")
lastrow = Worksheets("Word_Files").UsedRange.Rows.Count + 1
totTbl = objDoc.Tables.Count
Debug.Print totTbl
For Each oTbl In objDoc.Tables
strCellText = oTbl.cell(1, 1).Range.Text
strCellText = LCase(strCellText)
Debug.Print strCellText
If strCellText Like "*data input*" Then
Worksheets("Word_Files").Range("A" & lastrow) = strFolder & strFile
On Error Resume Next
If cnt = 1 Then
lastrow = lastrow
Else
lastrow = ActiveSheet.UsedRange.Rows.Count
End If
oTbl.Range.Copy
Range("B" & lastrow).Select
sht.Paste
cnt = cnt + 1
End If
Next oTbl
End If
filecounter = filecounter + 1
Debug.Print filecounter
objWord.Close
Next cell
objDoc.Quit
Set objDoc = Nothing
objWord.Quit
Set objWord = Nothing
SecondsElapsed = Round(Timer - StartTime, 2)
SecondsFinal = SecondsElapsed / 60
MsgBox ("Code ran in " & SecondsFinal & "minutes.")
End Sub

How to extract headings from Word files to Excel?

I have hundreds of Word files (docx) which each have various headings, defined as Heading 1, Heading 2, Heading 3, etc. Each of these files has a table of contents which correspond to the headings.
I want to extract each heading from each of these files into an Excel workbook to build a database.
My first attempt was to extract the headings from a single Word document into an Excel workbook. I found code online to extract headings from Word to Outlook, and also separate code to extract headings from Word to a new Word file.
I haven't been able to adapt either of these.
How do I extract headings from a single Word file to Excel? I will then try to work out further steps.
Word to Outlook
Sub CopyHeadingsIntoOutlookMail()
Dim objOutlookApp, objMail As Object
Dim objMailDocument As Word.Document
Dim objMailRange As Word.Range
Dim varHeadings As Variant
Dim i As Long
Dim strText As String
Dim nLongDiff As Integer
'Create a new Outlook email
Set objOutlookApp = CreateObject("Outlook.Application")
Set objMail = objOutlookApp.CreateItem(olMailItem)
objMail.Display
Set objMailDocument = objMail.GetInspector.WordEditor
Set objMailRange = objMailDocument.Range(0, 0)
'Get the headings of the current Word document
varHeadings = ActiveDocument.GetCrossReferenceItems(wdRefTypeHeading)
For i = LBound(varHeadings) To UBound(varHeadings)
strText = Trim(varHeadings(i))
'Get the heading level
nLongDiff = Len(RTrim$(CStr(varHeadings(i)))) - Len(Trim(CStr(varHeadings(i))))
nHeadingLevel = (nLongDiff / 2) + 1
'Insert the heading into the Outlook mail
With objMailRange
.InsertAfter strText & vbNewLine
.Style = "Heading " & nHeadingLevel
.Collapse wdCollapseEnd
End With
Next i
End Sub
Word to Word
Public Sub CreateOutline()
Dim docOutline As Word.Document
Dim docSource As Word.Document
Dim rng As Word.Range
Dim astrHeadings As Variant
Dim strText As String
Dim intLevel As Integer
Dim intItem As Integer
Set docSource = ActiveDocument
Set docOutline = Documents.Add
' Content returns only the
' main body of the document, not
' the headers and footer.
Set rng = docOutline.Content
astrHeadings = _
docSource.GetCrossReferenceItems(wdRefTypeHeading)
For intItem = LBound(astrHeadings) To UBound(astrHeadings)
' Get the text and the level.
strText = Trim$(astrHeadings(intItem))
intLevel = GetLevel(CStr(astrHeadings(intItem)))
' Add the text to the document.
rng.InsertAfter strText & vbNewLine
' Set the style of the selected range and
' then collapse the range for the next entry.
rng.Style = "Heading " & intLevel
rng.Collapse wdCollapseEnd
Next intItem
End Sub
Private Function GetLevel(strItem As String) As Integer
' Return the heading level of a header from the
' array returned by Word.
' The number of leading spaces indicates the
' outline level (2 spaces per level: H1 has
' 0 spaces, H2 has 2 spaces, H3 has 4 spaces.
Dim strTemp As String
Dim strOriginal As String
Dim intDiff As Integer
' Get rid of all trailing spaces.
strOriginal = RTrim$(strItem)
' Trim leading spaces, and then compare with
' the original.
strTemp = LTrim$(strOriginal)
' Subtract to find the number of
' leading spaces in the original string.
intDiff = Len(strOriginal) - Len(strTemp)
GetLevel = (intDiff / 2) + 1
End Function
Try the following Excel macro. When you run it, simply select the folder to process.
Sub GetTOCHeadings()
'Note: this code requires a reference to the Word object model.
'See under the VBE's Tools|References.
Application.ScreenUpdating = False
Dim wdDoc As Word.Document, wdRng As Word.Range, wdPara As Word.Paragraph
Dim strFolder As String, strFile As String
Dim WkSht As Worksheet, i As Long, j As Long
strFolder = GetFolder
If strFolder = "" Then Exit Sub
Dim wdApp As New Word.Application
Set WkSht = ActiveSheet
i = WkSht.Cells(WkSht.Rows.Count, 1).End(xlUp).Row
wdApp.WordBasic.DisableAutoMacros
wdApp.DisplayAlerts = wdAlertsNone
strFile = Dir(strFolder & "\*.doc", vbNormal)
While strFile <> ""
i = i + 1
Set wdDoc = wdApp.Documents.Open(Filename:=strFolder & "\" & strFile, AddToRecentFiles:=False, Visible:=False)
With wdDoc
j = 1: WkSht.Cells(i, j) = strFile
If .TablesOfContents.Count > 0 Then
With .TablesOfContents(1)
.IncludePageNumbers = False
.Update
Set wdRng = .Range
End With
With wdRng
.Fields(1).Unlink
For Each wdPara In .Paragraphs
j = j + 1
WkSht.Cells(i, j).Value = Replace(wdPara.Range.Text, vbTab, " ")
Next
End With
End If
.Close SaveChanges:=False
End With
strFile = Dir()
Wend
wdApp.DisplayAlerts = wdAlertsAll
wdApp.Quit
Set wdDoc = Nothing: Set wdApp = Nothing: Set WkSht = Nothing
Application.ScreenUpdating = True
End Sub
Function GetFolder() As String
Dim oFolder As Object
GetFolder = ""
Set oFolder = CreateObject("Shell.Application").BrowseForFolder(0, "Choose a folder", 0)
If (Not oFolder Is Nothing) Then GetFolder = oFolder.Items.Item.Path
Set oFolder = Nothing
End Function

Find String and extract in vba using fso

so my code currently goes through a folder and extracts Ranges of data from every file in the folder into a format set by me, it also extracts the filename.
Now i need to use fso to search for certain string inside the file not the filename, lets say "Smart", and in the file "Smart" appears quite a few times, but i only want to extract it once.
Thank you so much to anyone who is able to provide me the small part of the code or some advices to help me continue on!
Option Explicit
Sub ScanFiles()
Application.ScreenUpdating = False
Dim wks As Worksheet
Set wks = Worksheets.Add
' New worksheet for question 2
Dim wksFSO As Worksheet
' Add headers data
With wks
.Range("A1:E1") = Array("Test", "Temp", "Start", "Type", "FileName", "Test", "EndDate", "Smart", "Er")
End With
' Set your copy ranges
Dim CopyRange(1 To 4) As String
CopyRange(1) = "A18"
CopyRange(2) = "A19"
CopyRange(3) = "A14"
CopyRange(4) = "A19"
' Early Binding - Add "Microsoft Scripting Runtime" Reference
Dim FSO As New Scripting.FileSystemObject
' Set FolderPath
Dim FolderPath As String
FolderPath = "c:\Users\Desktop\Tryout\"
' Set Folder FSO
Dim Folder As Scripting.Folder
Set Folder = FSO.GetFolder(FolderPath)
' Loop thru each file -> Assuming only 6 files
Dim File As Scripting.File
For Each File In Folder.Files
' If loop looking for specific files and copy to new FSOWorksheet
If File.Name Like "ReportFile" Then
wksFSO.Cells(1, 1) = File.Name
End If
Dim wkbData As Workbook
Set wkbData = Workbooks.Open(File.Path)
Dim wksData As Worksheet
ActiveSheet.Name = "Sheet1"
Set wksData = wkbData.Worksheets("Sheet1") ' -> Assume this file has only 1 worksheet
Dim BlankRow As Long
BlankRow = wks.Range("A" & wks.Rows.Count).End(xlUp).Row + 1
Dim i As Long
For i = 1 To 4
wks.Cells(BlankRow, i).Value = wksData.Range(CopyRange(i)).Value
Next i
' Write filename in col E
wks.Cells(BlankRow, 5).Value = File.Name
wkbData.Close False
Next File
Range("A:I").EntireColumn.AutoFit
Application.ScreenUpdating = True
End Sub
This could help you, what it does is it search through the path's folders and each excel file that is inside it for the word that you are going to put in the input box.
Sub SearchFolders()
Dim fso As Object
Dim fld As Object
Dim strSearch As String
Dim strPath As String
Dim strFile As String
Dim wOut As Worksheet
Dim wbk As Workbook
Dim wks As Worksheet
Dim lRow As Long
Dim rFound As Range
Dim strFirstAddress As String
On Error GoTo ErrHandler
Application.ScreenUpdating = False
'Change as desired
strPath = "c:\MyFolder"
'You can enter your smart word here
strSearch = inputbox("Please enter a word to be searched.","Search for a word")
Set wOut = Worksheets.Add
lRow = 1
With wOut
.Cells(lRow, 1) = "Workbook"
.Cells(lRow, 2) = "Worksheet"
.Cells(lRow, 3) = "Cell"
.Cells(lRow, 4) = "Text in Cell"
Set fso = CreateObject("Scripting.FileSystemObject")
Set fld = fso.GetFolder(strPath)
strFile = Dir(strPath & "\*.xls*")
Do While strFile <> ""
Set wbk = Workbooks.Open _
(Filename:=strPath & "\" & strFile, _
UpdateLinks:=0, _
ReadOnly:=True, _
AddToMRU:=False)
For Each wks In wbk.Worksheets
Set rFound = wks.UsedRange.Find(strSearch)
If Not rFound Is Nothing Then
strFirstAddress = rFound.Address
End If
Do
If rFound Is Nothing Then
Exit Do
Else
lRow = lRow + 1
.Cells(lRow, 1) = wbk.Name
.Cells(lRow, 2) = wks.Name
.Cells(lRow, 3) = rFound.Address
.Cells(lRow, 4) = rFound.Value
End If
Set rFound = wks.Cells.FindNext(After:=rFound)
Loop While strFirstAddress <> rFound.Address
Next
wbk.Close (False)
strFile = Dir
Loop
.Columns("A:D").EntireColumn.AutoFit
End With
MsgBox "Done"
ExitHandler:
Set wOut = Nothing
Set wks = Nothing
Set wbk = Nothing
Set fld = Nothing
Set fso = Nothing
Application.ScreenUpdating = True
Exit Sub
ErrHandler:
MsgBox Err.Description, vbExclamation
Resume ExitHandler
End Sub

Searching Multiple Excel file using VBA with multiple search variable and output to one sheet/CSV

I am trying to modify this code, to search multiple values, from a folder containing multiple excel files, and output it to a sheet or a CSV.
The code is able to search through multiple excel sheet and output the value but the problem is that it only outputs the first search value "search_a".
The code searches a folder for the value and puts it in a new sheet.
It gives the search results for search_a but not for the others search_b, search_c..... all the search result should be in one sheet.
I know i am making some simple mistake but i am unable to identify it.
I also tried to import the search values from a .txt file list but that did not work.
Sub SearchFolders()
Dim xFso As Object
Dim xFld As Object
Dim xStrSearch As Variant
Dim xStrPath As String
Dim xStrFile As String
Dim xOut As Worksheet
Dim xWb As Workbook
Dim xWk As Worksheet
Dim xRow As Long
Dim xFound As Range
Dim xStrAddress As String
Dim xFileDialog As FileDialog
Dim xUpdate As Boolean
Dim xCount As Long
Dim xStrS As Variant
On Error GoTo ErrHandler
Set xFileDialog = Application.FileDialog(msoFileDialogFolderPicker)
xFileDialog.AllowMultiSelect = False
xFileDialog.Title = "Select a forlder"
If xFileDialog.Show = -1 Then
xStrPath = xFileDialog.SelectedItems(1)
End If
If xStrPath = "" Then Exit Sub
xUpdate = Application.ScreenUpdating
Application.ScreenUpdating = False
Set xOut = Worksheets.Add
xRow = 1
With xOut
.Cells(xRow, 1) = "Workbook"
.Cells(xRow, 2) = "Worksheet"
.Cells(xRow, 3) = "Cell"
.Cells(xRow, 4) = "Text in Cell"
Set xFso = CreateObject("Scripting.FileSystemObject")
Set xFld = xFso.GetFolder(xStrPath)
xStrFile = Dir(xStrPath & "\*.xls*")
xStrSearch = Array("search_a", "search_b", "search_c", "search_d", "search_e", "search_f")
For Each xStrS In xStrSearch
Do While xStrFile <> ""
Set xWb = Workbooks.Open(Filename:=xStrPath & "\" & xStrFile, UpdateLinks:=0, ReadOnly:=True, AddToMRU:=False)
For Each xWk In xWb.Worksheets
Set xFound = xWk.UsedRange.Find(xStrSearch)
If Not xFound Is Nothing Then
xStrAddress = xFound.Address
End If
Do
If xFound Is Nothing Then
Exit Do
Else
xCount = xCount + 1
xRow = xRow + 1
.Cells(xRow, 1) = xWb.Name
.Cells(xRow, 2) = xWk.Name
.Cells(xRow, 3) = xFound.Address
.Cells(xRow, 4) = xFound.Value
End If
Set xFound = xWk.Cells.FindNext(After:=xFound)
Loop While xStrAddress <> xFound.Address
Next
xWb.Close (False)
xStrFile = Dir
Loop
Next
.Columns("A:D").EntireColumn.AutoFit
End With
ExitHandler:
Set xOut = Nothing
Set xWk = Nothing
Set xWb = Nothing
Set xFld = Nothing
Set xFso = Nothing
Application.ScreenUpdating = xUpdate
Exit Sub
ErrHandler:
MsgBox Err.Description, vbExclamation
Resume ExitHandler
End Sub
I want the search result for all the search values in one sheet or csv.
I couldn't test my code fully, but from the little testing I did do, it seemed to work:
Option Explicit
Private Function GetFolderPath(ByRef folderPathSelected As String) As Boolean
Dim xFileDialog As FileDialog
Set xFileDialog = Application.FileDialog(msoFileDialogFolderPicker)
xFileDialog.AllowMultiSelect = False
xFileDialog.Title = "Select a folder"
If xFileDialog.Show = -1 Then
folderPathSelected = xFileDialog.SelectedItems(1)
GetFolderPath = True
End If
End Function
Private Function GetAllExcelFilesInFolder(ByVal someFolderPath As String, Optional ByVal dirCriteria As String = "*.xls*") As Collection
' Could probably use FileSystemObject instead for this.
Dim outputCollection As Collection
Set outputCollection = New Collection
If Right$(someFolderPath, 1) <> "\" Then
someFolderPath = someFolderPath & "\"
End If
Dim Filename As String
Filename = Dir$(someFolderPath & dirCriteria)
Do Until Len(Filename) = 0
outputCollection.Add someFolderPath & Filename
Filename = Dir$()
Loop
Set GetAllExcelFilesInFolder = outputCollection
End Function
Private Function MaybeUnion(ByVal firstRange As Range, ByVal secondRange As Range) As Range
' Assumes firstRange is good (and doesn't need checking).
If Not (secondRange Is Nothing) Then
Set MaybeUnion = Union(firstRange, secondRange)
Else
Set MaybeUnion = firstRange
End If
End Function
Private Function FindAllInWorkbook(ByVal someWorkbook As Workbook, _
ByVal What As String, _
Optional ByVal LookIn As XlFindLookIn = xlValues, _
Optional ByVal LookAt As XlLookAt = xlWhole, _
Optional SearchOrder As XlSearchOrder = xlByRows, _
Optional SearchDirection As XlSearchDirection = xlNext, _
Optional ByVal MatchCase As Boolean = False) As Range
Dim outputRange As Range
Dim targetSheet As Worksheet
For Each targetSheet In someWorkbook.Worksheets
Dim cellFound As Range
Set cellFound = targetSheet.Cells.Find(What, , LookIn, LookAt, LookAt, SearchOrder, SearchDirection, MatchCase)
If Not (cellFound Is Nothing) Then
Dim addressOfFirstMatch As String
addressOfFirstMatch = cellFound.Address
Do
Set outputRange = MaybeUnion(cellFound, outputRange)
Set cellFound = targetSheet.Cells.FindNext(After:=cellFound)
Loop Until cellFound.Address = addressOfFirstMatch
End If
Next targetSheet
Set FindAllInWorkbook = outputRange
End Function
Private Sub FindStringsInWorkbooks()
Dim folderPath As String
If Not GetFolderPath(folderPath) Then Exit Sub
Dim filePathsToProcess As Collection
Set filePathsToProcess = GetAllExcelFilesInFolder(folderPath)
Dim stringsToSearchFor As Variant
stringsToSearchFor = Array("search_a", "search_b", "search_c", "search_d", "search_e", "search_f")
Dim outputSheet As Worksheet
Set outputSheet = ThisWorkbook.Worksheets.Add
outputSheet.Range("A1:D1") = Array("Workbook", "Worksheet", "Cell", "Text in Cell")
Dim outputRowIndex As Long
outputRowIndex = 1 ' Skip header row
Dim filePath As Variant
For Each filePath In filePathsToProcess
Dim targetBook As Workbook
Set targetBook = Application.Workbooks.Open(Filename:=filePath, UpdateLinks:=0, ReadOnly:=True, AddToMRU:=False)
Dim stringToFind As Variant
For Each stringToFind In stringsToSearchFor
Dim cellsFound As Range
Set cellsFound = FindAllInWorkbook(targetBook, stringToFind, xlValues, xlWhole, xlByRows, xlNext, False)
If Not (cellsFound Is Nothing) Then
Dim cell As Range
For Each cell In cellsFound
outputRowIndex = outputRowIndex + 1
With outputSheet
.Cells(outputRowIndex, "A") = targetBook.Name
.Cells(outputRowIndex, "B") = cell.Parent.Name
.Cells(outputRowIndex, "C") = cell.Address
.Cells(outputRowIndex, "D") = cell.Value
End With
Next cell
Else
Debug.Print "No results found for '" & stringToFind & "' in workbook '" & targetBook.Name & "'."
End If
Next stringToFind
targetBook.Close SaveChanges:=False
Next filePath
End Sub
If wanted:
It's good to take advantage of functions/procedures in your code, so that the code is a bit easier to read.
Since you aren't making changes to the workbook/worksheets inside the loop, it should be okay for you to return all matches first and then process them later altogether (rather than processing them as you find them).
I think it makes sense to have the workbook loop on the outside, and the search term loop on the inside. Otherwise, you will be opening and closing the same workbook N times (where N is how ever many search terms you have). However, this does mean that the order of the output/results will be different.
You may need to re-implement formatting (e.g. auto-fit column widths and so on) -- and toggle Application.ScreenUpdating as necessary.

Copy data from several Word documents to one Excel workbook using Word VBA

I have about 100 Word documents and from each I want to copy data and paste it all in one Excel workbook.
I came up with this code which opens one Word document, copies data, pastes it to Excel and closes the Word document:
Sub WordDataToExcel()
Dim myObj
Dim myWB
Dim mySh
Dim txt As String, Lgth As Long, Strt As Long
Dim i As Long
Dim oRng As Range
Dim Tgt As String
Dim TgtFile As String
Dim arr()
Dim ArrSize As Long
Dim ArrIncrement As Long
ArrIncrement = 1000
ArrSize = ArrIncrement
ReDim arr(ArrSize)
Dim wrdDoc As Object
Documents.Open ("D:\ekr5_i.doc")
TgtFile = "result.xlsx"
Tgt = "D:\" & TgtFile
'finds the text string of Lgth lenght
txt = "thetext"
Lgth = 85
Strt = Len(txt)
'Return data to array
With Selection
.HomeKey unit:=wdStory
With .Find
.ClearFormatting
.Forward = True
.Text = txt
.Execute
While .Found
i = i + 1
Set oRng = ActiveDocument.Range _
(Start:=Selection.Range.Start + Strt, _
End:=Selection.Range.End + Lgth)
arr(i) = oRng.Text
oRng.Start = oRng.End
.Execute
If i = ArrSize - 20 Then
ArrSize = ArrSize + ArrIncrement
ReDim Preserve arr(ArrSize)
End If
Wend
End With
End With
ReDim Preserve arr(i)
'Set target and write data
Set myObj = CreateObject("Excel.Application")
Set myWB = myObj.Workbooks.Open(Tgt)
Set mySh = myWB.Sheets(1)
With mySh
.Range(.Cells(1, 1), .Cells(i, 1)) = myObj.Transpose(arr)
End With
'Tidy up
myWB.Close True
myObj.Quit
ActiveDocument.Close SaveChanges:=wdDoNotSaveChanges
Set mySh = Nothing
Set myWB = Nothing
Set myObj = Nothing
End Sub
I need to loop through all the documents in the folder.
I have implemented the same with Excel workbooks, but I don't know how for Word documents.
Here is the code for Excel workbooks:
Sub combine_into_one()
Dim FSO As Object: Set FSO = CreateObject("Scripting.FileSystemObject")
Dim strPath$, Pivot$, sUserName$, sFolderName$, sSourceName$, x&
Dim oFldialog As FileDialog
Dim oFolder
Application.DisplayAlerts = False
Application.ScreenUpdating = False
Set oFldialog = Application.FileDialog(msoFileDialogFolderPicker)
With oFldialog
If .Show = -1 Then
.Title = "Select a Folder"
.AllowMultiSelect = False
.InitialFileName = strPath
sFolderName = .SelectedItems(1)
End If
End With
Set oFolder = FSO.GetFolder(sFolderName)
Workbooks.Add: Pivot = ActiveWorkbook.Name 'Destination workbook
For Each oFile In oFolder.Files
Workbooks(Pivot).Activate
x = Workbooks(Pivot).Sheets(1).Cells.SpecialCells(xlCellTypeLastCell).Row + 1
Workbooks.Open Filename:=oFile: sSourceName = ActiveWorkbook.Name
Workbooks(sSourceName).Activate
Workbooks(sSourceName).Sheets(1).[A80:Q94].copy
Workbooks(Pivot).Activate
Workbooks(Pivot).Sheets(1).Cells(x + 1, 1).PasteSpecial xlPasteAll
Workbooks(sSourceName).Close False
Next
Application.CutCopyMode = False
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub
There are so, so, so many things you can do between Excel & Word. I'm not sure I totally understand your question. The script below may help you; it has definitely served me well over time. If you need something different, please describe your issue more, to better clarify the issue you are facing.
Sub OpenAndReadWordDoc()
Rows("2:1000000").Select
Range(Selection, Selection.End(xlDown)).Select
Selection.ClearContents
Range("A1").Select
' assumes that the previous procedure has been executed
Dim oWordApp As Word.Application
Dim oWordDoc As Word.Document
Dim blnStart As Boolean
Dim r As Long
Dim sFolder As String
Dim strFilePattern As String
Dim strFileName As String
Dim sFileName As String
Dim ws As Worksheet
Dim c As Long
Dim n As Long
'~~> Establish an Word application object
On Error Resume Next
Set oWordApp = GetObject(, "Word.Application")
If Err Then
Set oWordApp = CreateObject("Word.Application")
' We started Word for this macro
blnStart = True
End If
On Error GoTo ErrHandler
Set ws = ActiveSheet
r = 1 ' startrow for the copied text from the Word document
' Last column
n = ws.Range("A1").End(xlToRight).Column
sFolder = "C:\Users\Excel\Desktop\Coding\Microsoft Excel\PWC\Resumes\"
'~~> This is the extension you want to go in for
strFilePattern = "*.doc*"
'~~> Loop through the folder to get the word files
strFileName = Dir(sFolder & strFilePattern)
Do Until strFileName = ""
sFileName = sFolder & strFileName
'~~> Open the word doc
Set oWordDoc = oWordApp.Documents.Open(sFileName)
' Increase row number
r = r + 1
' Enter file name in column A
ws.Cells(r, 1).Value = sFileName
ActiveCell.Offset(1, 0).Select
ActiveSheet.Hyperlinks.Add Anchor:=Sheets("Sheet1").Range("A" & r), Address:=sFileName, _
SubAddress:="A" & r, TextToDisplay:=sFileName
' Loop through the columns
For c = 2 To n
If oWordDoc.Content.Find.Execute(FindText:=Trim(ws.Cells(1, c).Value), _
MatchWholeWord:=True, MatchCase:=False) Then
' If text found, enter Yes in column number c
ws.Cells(r, c).Value = "Yes"
End If
Next c
oWordDoc.Close SaveChanges:=False
'~~> Find next file
strFileName = Dir
Loop
ExitHandler:
On Error Resume Next
' close the Word application
Set oWordDoc = Nothing
If blnStart Then
' We started Word, so we close it
oWordApp.Quit
End If
Set oWordApp = Nothing
Exit Sub
ErrHandler:
MsgBox Err.Description, vbExclamation
Resume ExitHandler
End Sub
Function GetDirectory(path)
GetDirectory = Left(path, InStrRev(path, "\"))
End Function
In this scenario, whatever you put in the headers of B1:K1 (or more to the right) is searched for, each word document in a folder is opened, scanned, and if the string in B1:K1 is found, an 'x' is placed in the same x-y coordinate.
Again, if this doesn't help, please describe your issue better, and I'll post back with alternative solutions. Thanks!!

Resources