VBA outputting text file data into excel with mapping table - vba

I am trying to create a VBA script which will read Text Files which I have converted from PDF Files and pull out key information following search words. All the Text Files will be located in a central location C:Work\Text
Within each of these Text Files is information that I would like to pull out and put into columns within Excel. The search word helps identify the information but the search word may be different in each of the Text Files, so I will need to create a Table of search words. And once it finds the information in one text file it can move onto the next one it doesn't need to post every instance of the search word appearing in the text file.
Example:
I am looking for Account Numbers and Amounts
Text File 1: Account Number can be found within the text file by Searching the word "Account Number:" and Amount can be found by searching "Amount:"
Account Number: 1234
Amount: $10
Text File 2: Account Number can be found within the text file by Searching the word "Account" and Amount can be found by searching "Cost"
Account 00090
Cost 25
Text File 3: Account Number can be found within the text file by Searching the word "Initial Number" and Amount can be found by searching "Total"
Initial Number 555555555
Total $90.02
Etc
So essential I would want to create a mapping table that references these Search Words and for it to just bring in the information after the search word . If a new search word needs to be added I could always just add to the mapping table.
The output would essential put All the Account Number data into Column A1 and all the Amount Data will go into B1

I wrote sample code to give pointers. You may need to iterate the same piece for rest. You may add multiple if conditions to search for the other patterns(just a suggestion)
Const ForReading = 1
Dim strSearchFor
dim i=1
Set objExcel = CreateObject("Excel.Application")
‘Set objWorkbook = objExcel.Workbooks.Open("C:\test.xls")
objExcel.Application.Visible = True
objExcel.Workbooks.Add
For Each f In objFSO.GetFolder("C:\some\folder").Files
Set objFile = f.OpenAsTextStream
strSearchFor = "Account Number"
Do Until objFile.AtEndOfStream
strLine = objFile.ReadLine
'do stuff with strLine and append to strText
If InStr(strLine, strSearchFor) <> 0 then
Wscript.Echo "Account Number found"
objExcel.Cells(i, 1).Value = strLine
i=i+1
Else
Wscript.Echo "Account Number not found"
End If
Loop
objFile.Close
Next
objExcel.ActiveWorkbook.SaveAs "C:\test.xls"
objExcel.ActiveWorkbook.Close
objExcel.Application.Quit

Related

How to change filename using macro?

Now I have a document and i want to save it but the filename should be iterative
eg. 1.docx then if i run the macro it should save as 2.docx and so on.
can I take a word from the document as the variable for the filename
eg. I want to use the 45th word in my document as the filename
So how can i do it?
I don't have word open at the moment, so cannot code specific examples. What follows is hints on how to find your answer.
In word, you can select a range of text. Within these ranges are a number of built-in collections. "Paragraphs" and "Words" are some of the examples.
The easiest way to address your question is to select the Document Range, and then iterate through the Words collection until you get to the 45th word.
However, MSDN notes that some non-words are also kept in this collection, so you may want to filter as you iterate. (as an aside, be careful with their example, deleting items in a for-each loop has consequences)
Assuming "rngWords" is your selected document range (words collection), you could would be similar to (not true code):
Counter = 0
selectedWord = ""
for iterator = 1 to rngWords.Count
loopWord = rngWords(iterator)
if trueword then Counter = Counter + 1
if counter = 45 then ' magic number = 45 based on your post.
selectedword = loopWord
exit loop
end if
next iterator
You can experiment (e.g. debug.print loopWord) to work out how to determine a true word. You will also have to address what happens if you don't have 45 words in your document - e.g. you could take the last word. Probably the best way is to check the count first (if rngWords.Count < 45 then .... else (loop))
To retrieve the no. from from document, use the below link
Getting char from string at specified index in the visual basic
and for saving the file
Sub ExampleToSaveWorkbook()
Workbooks.Add
'Saving the Workbook
ActiveWorkbook.SaveAs "C:\WorkbookName.xls"
'OR
'ActiveWorkbook.SaveAs Filename:="C:\WorkbookName1.xls"
End Sub

Excel Macro to read multiple files in a folder and search in it

I have some excel workbooks of same header rows. I need to search in a particular column in all these workbooks and do a countif kind of functionality in a corresponding column( different than the first column)
For eg.. Column A has names of boxes, B has information about the contents in each box. I would like to search multiple excels in folder and get a report of unique box names and their content counts. Box A has 5 apples, 2 oranges , 1 mango.
I hope this requirement is clear enough. Could anyone help me with a base axcel macro code?
Talking about workbooks you have different files (*.xls) in one folder? Then you can start with something like this:
Dim Path As Integer
Path = "Type in the path with your workbooks"
File = Dir$(Path & "\*.xls")
Do While File <> ""
'Do stuff like:
'opening your workbook and search for the names of the boxes
'save your needed informations in a variable or array
'close the workbook
File = Dir$()
Loop
Or do you mean you have one workbook (one file) with more worksheets? Then do something like this:
Dim i
For i = 1 To ThisWorkbook.Worksheets.Count
'Do your stuff here
Next i
If you want to get better help please post some of your code with specific questions

Automating Mail Merge

I need to dynamically generate word documents using text from an Access database table. The caveat here is that some of the text coming from the database will need to be modified into MergeFields. I am currently using Interop.Word (VBA Macro) and VB.NET to generate the document.
My steps so far look like this:
Pull standard .docx Template
Fill In template with pre-defined filler text from table
Add MergeFields by replacing pieces of the filler text with actual mergefields
Attach Datasource and execute Mail Merge
After testing, I noticed that I cannot simply store MergeFields into the access database as a string, they do not feed over into the actual document. What I am thinking then is creating a table of known strings that should be replaced with MergeFields by the coding.
For Example:
Step 2 will insert "After #INACTIVE_DATE# your account will no longer be active." which will be in the database text.
Step 3 will find/replace #INACTIVE_DATE# with a MergeField «INACTIVE_DATE». I am using Word Interop to do this, so theoretically I can loop through the document.
I wasnt able to do a "Find And Replace" from text to MergeField, so how should I go about implementing this?
Tagging VBA additionally as I am seeking a "VBA" style answer (Word Interop).
You've left out quite a lot of detail, so I'll go about answering this in somewhat general terms.
What you want to do is definitely achievable. Two possible solutions immediately come to mind:
Replacing ranges using Find
Inserting tokens using TypeText
Replacing ranges using Find
Assuming the text has already been inserted, you can search the document for the given pattern and replace it with a merge field. For instance:
Sub FindInsertMerge()
Dim rng As Range
Set rng = ActiveDocument.Range
With rng.Find
.Text = "(\#*\#)"
.MatchWildcards = True
.Execute
If .Found Then
ActiveDocument.MailMerge.Fields.Add rng, Mid(rng.Text, 2, Len(rng.Text) - 2)
End If
End With
End Sub
Will find the first occurence of text starting with #, matches any string and ends with #. The contents of the found range will then be replaced by a merge field. The code above can easily be extended to loop for all fields.
Inserting tokens using TypeText
While I would normally advice against using Selection to insert data, this solution makes things simple. Say you have a target range, rng, you tokenize the database text to be inserted, select the range, start typing and whenever a designated mail merge field is found, insert a field instead of the text.
For instance:
Private Sub InsertMergeText(rng As Range, txt As String)
Dim i As Integer
Dim t As String
Dim tokens() As String
tokens = Split(txt, " ")
rng.Select
For i = 0 To UBound(tokens)
t = tokens(i)
If Left(t, 1) = "#" And Right(t, 1) = "#" Then
'Insert field if it's a mail merge label.
ActiveDocument.MailMerge.Fields.Add Selection.Range, Mid(t, 2, Len(t) - 2)
Else
'Simply insert text.
Selection.TypeText t
End If
'Insert the whitespace we replaced earlier.
If i < UBound(tokens) Then Selection.TypeText " "
Next
End Sub
Call example:
InsertMergeText Selection.Range, "After #INACTIVE_DATE# your account will no longer be active which will be in the database text."

MS Word Mail Merge and Split Documents saving, Header and footer issue

I am using the below Macro to split the mail merged into separate documents. What I need is it to split into separate documents keeping the whole page including the header and footers and saving as in the first merged field on the page, which is the first piece of information on the merged letters.
However, the macro runs only on one letter not the rest, and the format is completely incorrect. It changes the font, page layout and does not include the headers and footers. It also saves as 'Ref' rather than the first merged field on the letter.
Does anyone have any idea how to amend the code below so it correctly updates with the above and for all letters please? I understand if this looks really bad but I am new to VBA and no one on my project to ask for help. Thanks in advance
Sub splitter()
' Based on a macro by Doug Robbins to save each letter created by a mailmerge as a separate file.
' With help from http://www.productivitytalk.com/forums/topic/3927-visual-basic-question-for-merge-fields/
Dim i As Integer
Dim Source As Document
Dim Target As Document
Dim Letter As Range
Dim oField As Field
Dim Ref As String
Set Source = ActiveDocument
For i = 1 To Source.Sections.Count
Set Letter = Source.Sections(i).Range
Letter.End = Letter.End - 1
For Each oField In Letter.Fields
If oField.Type = wdFieldMergeField Then
If InStr(oField.Code.Text, "Ref") > 0 Then
'get the result and store it the Ref variable
Ref = oField.Result
End If
End If
Next oField
Set Target = Documents.Add
Target.Range = Letter
Target.SaveAs FileName:="\\svr4958file01\Libraries\u20480\Documents\On Hold letters Template\20150512 On hold Letters Customers Active and Cancelled\" & "Ref"
Target.Close
Next i
End Sub
Offering an alternative answer to this old question as I recently had to solve it myself, and this question still ranks high up the results when searching for this issue.
I started with the macro at https://word.tips.net/T001538_Merging_to_Individual_Files.html, modifying it to first create separate blank documents based on the mail merge file, to preserve headers, footers and formatting. This may be an inefficient method, but doesn't require messing around with templates.
The following macro should be run from the mail merge output document which needs to be split.
Sub BreakOnSection()
'***Update the working folder location below***
ChangeFileOpenDirectory "C:\C:\Users\User\Downloads"
'***Update the original mail merge file name below***
mailmergeoriginal = "Original Mail merge.docx"
'Makes code faster and reduces screen flicker
Application.ScreenUpdating = False
'Used to set criteria for moving through the document by section.
Application.Browser.Target = wdBrowseSection
SectionCount = ActiveDocument.Sections.Count
'Save a template for each mailmerge document
ActiveDocument.StoryRanges(wdMainTextStory).Delete
DocNum = 1
For i = 1 To (SectionCount - 1)
ActiveDocument.SaveAs FileName:="Mail merge " & DocNum & ".docx"
DocNum = DocNum + 1
Next i
ActiveDocument.SaveAs FileName:="Macro temp.docx"
Documents.Open FileName:= mailmergeoriginal
Documents("Combined Offers.docx").Activate
'A mailmerge document ends with a section break next page
DocNum = 1
For i = 1 To (SectionCount - 1)
'Select and copy the section text to the clipboard
ActiveDocument.Bookmarks("\Section").Range.Copy
'Create a new document to paste text from clipboard
Documents.Open FileName:="Mail merge " & DocNum & ".docx"
'To save your document with the original formatting'
Selection.PasteAndFormat (wdFormatOriginalFormatting)
'Removes any break copied at the end of the section
Selection.MoveUp Unit:=wdLine, Count:=1, Extend:=wdExtend
Selection.Delete Unit:=wdCharacter, Count:=1
ActiveDocument.SaveAs FileName:="Mail merge " & DocNum & ".docx"
ActiveDocument.Close
DocNum = DocNum + 1
'Move the selection to the next section in the document
Application.Browser.Next
Next i
End Sub
Please note that this macro will leave one extra file behind after running, called "Macro temp.docx", which I needed to keep open to keep the macro running. This file can safely be deleted after completion. This could probably be avoided, but I wanted to avoid needing to run the macro from a template and haven't come up with a better method.
This is just an answer to the second part:
This line:
If InStr(oField.Code.Text, "Ref") > 0 Then
Is finding the mergefield with "Ref" in it. If you need a different mergefield, you should put the name of the mergefield you wish to save the file as where "Ref" is, so if your mergefield is, "Addressee" then change it to:
If InStr(oField.Code.Text, "Address") > 0 Then
Also, your last line is saving the filename with the STRING "Ref" instead of the variable. You need to remove the quotes around Ref. It should read:
Target.SaveAs FileName:="\\svr4958file01\Libraries\u20480\Documents\On Hold letters Template\20150512 On hold Letters Customers Active and Cancelled\" & Ref
As far as the rest, you could use an alternative approach (I don't really have time to provide code for this right now). Find the first and last page of each range (which is set to variable Letter) and print out these pages to a word doc. This will keep the headers and footers. The code you will need to enter will be:
Letter.Information(wdActiveEndPageNumber)
to get the page number of the end of the range (not sure but I assume (wdActiveStartPageNumber) or something similar will get the first page of the range
and
Application.PrintOut From:=FirstPageNum, To:=LastPageNum, OutputFileName:=:="\\svr4958file01\Libraries\u20480\Documents\On Hold letters Template\20150512 On hold Letters Customers Active and Cancelled\" & Ref & ".doc"
Will update more later if I get the time.

Error 1004 with VBA code with bookmarks

I am using a macro to populate a word document with text from named ranges in excel. The word document has bookmarks that correspond with the named excel ranges. I did not write the code, but rather copied it from another source.
There is quite a bit more to this macro than the snippet I posted. I could post the rest if that is useful. I had about half of my word document bookmarked and the macro was working fine then it suddenly stopped working.
I am receiving a error 1004 in the line highlighted below. I am a newbie so I'm not even quite sure what I should be searching for to fix this issue. Any assistance you could provide would be appreciated! Thanks in advance!
P.S. In case it's relevant, I am using Word and Excel 2007
'PASTE TEXT STRINGS LOOP
n = 1
For Each temp In BkmTxt
p = p + 1
Prompt = "Please wait. Copying text. Carrying out operation " & p & " of " & pcount & "."
Application.StatusBar = Prompt
'If The Bkmtxt(n) is empty then go to the next one, once that has been found do next operation.
If BkmTxt(n) = Empty Then
n = n + 1
'should find match and work
Else
'You might want to use multiple copies of the same text string.
'In this case you need to call the bookmark as follows: "ARTextWhatever_01"
'You can use as many bookmarks as you want.
BkmTxtSplit = Split(BkmTxt(n), "_")
vValue = Range(BkmTxtSplit(0)).Text **<----- ERROR HERE**
Set wdRng = wdApp.ActiveDocument.Bookmarks(BkmTxt(n)).Range
If Len(sFormat) = 0 Then
'replace the bookmark text
wdRng.Text = vValue
Else
'replace the bookmark text with formatted text
wdRng.Text = Format(vValue, sFormat)
End If
'Re-add the Bookmark
wdRng.Bookmarks.Add BkmTxt(n), wdRng
n = n + 1
End If
Next
Step 1: Don't copy code from external sources. Use external sources as a learning tool and try to understand what they are actually doing.
Now if I understand you correctly, you simply have an Excel sheet with named ranges, I assume they have information already within them, and a word document with bookmarks that EXACTLY match the named ranges:
Step 2: Make sure you have the word object library reference within excel
Here:
sub KeepItDoin()
dim xlRange as Excel.Range
dim wdApp as new Word.Application
dim wdDoc as Word.Document
dim wdBkm as Word.Bookmark
set wdDoc = wdApp.Documents.Open( "Filepath" ) 'get filepath from where ever
for each wdBkm in wdDoc.Bookmarks
set xlRange = Application.Range(wdBkm.Name)
wdBkm.range.text = xlRange.Value
next wdBkm
end sub
That will get you close probably (didn't test, don't care if it works. Use it to learn). The idea is that if the bookmarks match up to the range, we can use their names to find the ranges in excel and then tell excel to move the data within it into the bookmarks range.
You will likely need to add some formatting or maybe create a table and then move cell by cell in the range and fill the table but this is as close as I'm willing to get since you like to copy pasta.
In case anyone is interested, I figured it out. There was an error with the bookmarks I inserted into my Word document. This macro returns Error 1004 if the word document contains a bookmark that does not correspond to a range in excel. Thank you for your help.