Do a simple calculation in word using VBA - vba

I have many documents i need to edit, i have the Version of the document in the Header like "Version #" these documents have different versions, but are all a single integer value. These versions need to +1 so i need to get the number then just add 1 then save.
This is seeming pretty tricky and im not sure its possible. Any Help would be appreciated.
For example.
Old Document
"Version 2"
New Edit
"Version 3"
I can find and replace as i have learned from here.

Try:
Sub UpdateVersions()
Application.ScreenUpdating = False
Dim strFolder As String, strFile As String, strDocNm As String
Dim wdDoc As Document, wdSctn As Section, wdHdFt As HeaderFooter
strDocNm = ActiveDocument.FullName
strFolder = GetFolder: If strFolder = "" Then Exit Sub
strFile = Dir(strFolder & "\*.doc", vbNormal)
While strFile <> ""
If strFolder & "\" & strFile <> strDocNm Then
Set wdDoc = Documents.Open(FileName:=strFolder & "\" & strFile, AddToRecentFiles:=False, Visible:=False)
With wdDoc
For Each wdSctn In .Sections
With wdSctn
For Each wdHdFt In .Headers
With wdHdFt
If .LinkToPrevious = False Then
With .Range
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = "Version [0-9]{1,}"
.Replacement.Text = ""
.Format = False
.Forward = True
.Wrap = wdFindStop
.MatchWildcards = True
.Execute
End With
Do While .Find.Found = True
.Text = "Version " & Split(.Text, " ")(1) + 1
.Collapse wdCollapseEnd
.Find.Execute
Loop
End With
End If
End With
Next
End With
Next
.Close SaveChanges:=True
End With
End If
strFile = Dir()
Wend
Set wdDoc = 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

This is a quick hack that may do what you wish.
First of all, make sure that you have the Scripting Runtime referenced in the Tools>Project>References menu. Secondly, I have understood that you have more than one document so this lot does everything in a folder.
I have just assumed, for this example, that the folder name is fixed. In Real Life you can modify the code to select the folder and then modify the code to go through sub-folders, but this is (a) a quick hack and (b) out of scope.
Public Sub IncreaseVersionNumbers()
' Make sure that the "Microsoft Scripting Runtime" library is enabled in the Tools>Projects>References
Dim sRootFolder As String
Dim oFSO As Scripting.FileSystemObject
Dim oFolder As Scripting.Folder
Dim oFile As Scripting.File
sRootFolder = "C:\_Documents\VersionNumberTest\" ' You can grab this by a Folder Selection dialog box instead
Set oFSO = New Scripting.FileSystemObject
Set oFolder = oFSO.GetFolder(sRootFolder)
For Each oFile In oFolder.Files
If InStr(1, oFile.Name, ".doc", vbTextCompare) > 0 Then
ProcessDocument (sRootFolder & oFile.Name)
End If
Next oFile
End Sub
Private Sub ProcessDocument(sDocument As String)
Dim oDoc As Word.Document
Dim oSection As Word.Section
Dim oRange As Range
Dim sHeaderText As String
On Error Resume Next
Set oDoc = Documents.Open(sDocument)
For Each oSection In oDoc.Sections
Set oRange = oSection.Headers(wdHeaderFooterPrimary).Range
If Not oRange Is Nothing Then
ProcessHeaderRange oRange
End If
Set oRange = oSection.Headers(wdHeaderFooterFirstPage).Range
If Not oRange Is Nothing Then
ProcessHeaderRange oRange
End If
Set oRange = oSection.Headers(wdHeaderFooterEvenPages).Range
If Not oRange Is Nothing Then
ProcessHeaderRange oRange
End If
Next oSection
oDoc.Close wdSaveChanges
End Sub
Private Sub ProcessHeaderRange(oRange As Range)
Dim sText As String, sNewText As String
Dim nPosn As Long, nStart As Long, nEnd As Long
Dim sVersion As String, nVersion As Long
sText = oRange.Text & " "
nPosn = InStr(1, sText, "Version", vbTextCompare)
If nPosn > 0 Then
nStart = InStr(nPosn, sText, " ")
If nStart > 0 Then
nStart = nStart + 1
nEnd = InStr(nStart, sText, " ")
If nEnd > 0 Then
sVersion = Mid$(sText, nStart, nEnd - nStart)
nVersion = Val(sVersion)
nVersion = nVersion + 1
sNewText = Left$(sText, nStart - 1) & Trim$(Str$(nVersion)) & " " & Right$(sText, Len(sText) - nEnd)
sNewText = Left$(sNewText, Len(sNewText) - 1)
oRange.Text = sNewText
End If
End If
End If
End Sub
This is, as I say, a quick hack so it may not work perfectly but, as always, have backups!
This works by going through each of the three possible headers in each possible section of the document. And if it finds a header in a section then it does what you say.
And this version does go above single digit version numbers. But it's a quick hack, as I say and so needs extra work to make it really bullet-proof. Having said that, it's a reasonable start I would think.
Hope that this helps,
Malc

Related

Add Page Number To Footer

I've got a bunch of documents that I need to add page numbering in the footer.
I tried writing a macro to do this but after I run there's still no page numbers (in header or footer)
Sub AddPageNumberToFooter()
Call DeleteExistingFooters
With ActiveDocument
.PageSetup.DifferentFirstPageHeaderFooter = False
.Sections(1).Footers(wdHeaderFooterPrimary).PageNumbers.Add
End With
End Sub
Sub DeleteExistingFooters()
Dim iSectionCnt As Integer
iSectionCnt = ActiveDocument.Sections.Count
If iSectionCnt > 0 Then
ActiveDocument.Sections(iSectionCnt).Footers(wdHeaderFooterPrimary).Range.Delete
End If
End Sub
What am I missing?
The following code will add Page #s to all documents lacking them in every page in the selected folder:
Sub UpdateDocumentFooters()
Application.ScreenUpdating = False
Dim strFolder As String, strFile As String
Dim wdDoc As Document, Sctn As Section, HdFt As HeaderFooter
strFolder = GetFolder: If strFolder = "" Then Exit Sub
strFile = Dir(strFolder & "\*.doc", vbNormal)
While strFile <> ""
If strFolder & "\" & strFile <> ThisDocument.FullName Then
Set wdDoc = Documents.Open(FileName:=strFolder & "\" & strFile, _
AddToRecentFiles:=False, Visible:=False)
With wdDoc
For Each Sctn In .Sections
For Each HdFt In Sctn.Footers
With HdFt
If .Exists Then
If Sctn.Index = 1 Then
Call AddPgFld(HdFt)
ElseIf .LinkToPrevious = False Then
Call AddPgFld(HdFt)
End If
End If
End With
Next
Next
.Close SaveChanges:=True
End With
End If
strFile = Dir()
Wend
Set wdDoc = Nothing
Application.ScreenUpdating = True
End Sub
Sub AddPgFld(HdFt As HeaderFooter)
Dim Fld As Field, bFld As Boolean
With HdFt
bFld = False
For Each Fld In .Range.Fields
If Fld.Type = wdFieldPage Then
bFld = True: Exit For
End If
Next
If bFld = False Then
With .Range.Paragraphs.Last.Range
If Len(.Text) > 2 Then .InsertAfter vbCr
End With
With .Range.Paragraphs.Last.Range
.Text = "Page "
.Fields.Add Range:=.Characters.Last, Type:=wdFieldEmpty, Text:="PAGE", PreserveFormatting:=False
.ParagraphFormat.Alignment = wdAlignParagraphCenter
End With
End If
End With
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
As you are writing that you have a bunch of documents: Could it be that ActiveDocument isn't the correct reference.
This works for me - you can replace ActiveDocument from the test-sub with any other document:
Option Explicit
Sub testPagenumbersForActiveDocument()
dim docToTest as Word.Document
set docToTest = ActiveDocument 'replace ActiveDocument with another doc you have opened
deleteExistingPageNumbers docToTest
addPageNumberToFooter docToTest
End Sub
Sub addPageNumberToFooter(doc As Word.Document)
With doc
.PageSetup.DifferentFirstPageHeaderFooter = False
.Sections(1).Footers(wdHeaderFooterPrimary).PageNumbers.Add
End With
End Sub
Sub deleteExistingPageNumbers(doc As Word.Document)
Dim sec As Section, pn As PageNumber
For Each sec In doc.Sections
For Each pn In sec.Footers(wdHeaderFooterPrimary).PageNumbers
pn.Delete
Next
Next
End Sub
The delete-sub only deletes PageNumbers - this is safer then your version as that will delete the whole footer-text ... which might be not what you want.

Adding new footer to a folder of word documents

I an using a code copied from "Macropod" (sorry if the name is incorrect) to replace every header and footer in a folder of documents with a new header and footer as displayed in the macro document. It is slightly altered to apply to only footers. This works, but my problem is that it leaves an extra paragraph mark on a line by itself at the end of the footer text and I cannot figure out where to add something that would remove the extra paragraph mark. When doing this copy/paste function manually, only a backspace is required to remove the extra paragraph mark. I've tried adding it a few different ways, but it either does nothing or produces an error. The macro text is provided below.
Sub UpdateDocumentFooters()
Application.ScreenUpdating = False
Dim strFolder As String, strFile As String
Dim wdDocTgt As Document, wdDocSrc As Document
Dim Sctn As Section, HdFt As HeaderFooter
strFolder = GetFolder
If strFolder = "" Then Exit Sub
Set wdDocSrc = ActiveDocument
strFile = Dir(strFolder & "\*.doc", vbNormal)
While strFile <> ""
If strFolder & "\" & strFile <> wdDocSrc.FullName Then
Set wdDocTgt = Documents.Open(FileName:=strFolder & "\" & strFile, _
AddToRecentFiles:=False, Visible:=False)
With wdDocTgt
For Each Sctn In .Sections
'For footers
For Each HdFt In Sctn.Footers
With HdFt
If .Exists Then
If Sctn.Index = 1 Then
wdDocSrc.Sections.First.Footers(HdFt.Index).Range.Copy
.Range.PasteAndFormat wdFormatOriginalFormatting
.Range.Characters.Last = vbNullString
ElseIf .LinkToPrevious = False Then
wdDocSrc.Sections.First.Footers(HdFt.Index).Range.Copy
.Range.PasteAndFormat wdFormatOriginalFormatting
.Range.Characters.Last = vbNullString
End If
End If
End With
Next
Next
.Close SaveChanges:=True
End With
End If
strFile = Dir()
Wend
Set wdDocSrc = Nothing: Set wdDocTgt = 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
Have reviewed the responses below, but no improvement yet.
I start with this:
Footer to Replace
And want to get this:
Desired Footer
But end up with this:
Resulting Footer

Looping through files in folder successfully but all files print corrupted error

This code is supposed to open all files in the subfolders of my target
folder and search them for specific terms, print those terms and where
they were found in a text file. If it encounters an error, print that
error so we know which documents to search manually.
It seems to be working, it's finding the search terms in the
documents, but then it prints an error message for each file in the
subfolder that it's corrupted? These files are fine to open, btw. They
don't appear to be corrupted in any way. They do have tracked changes
on, could that be why? I've included some sample output for one folder
below the code.
FINAL CODE: thanks so much everyone for your help
Option Explicit
Sub CheckCrossRef()
Dim FSO As Scripting.FileSystemObject
Dim masterFolder As folder
Dim allSubfolders As Folders
Dim currSubfolder As folder
Dim subfolderFiles As Files
Dim currFile As File
Set FSO = Nothing
Dim leftChar As String
Dim strFolder As String
Dim strDoc As String
Dim wordApp As Word.Application
Dim wordDoc As Word.Document
Dim nameArchive As Word.Document
Set wordApp = New Word.Application
wordApp.Visible = True
Set nameArchive = Documents.Add(Visible:=False)
Dim fd As FileDialog
Set fd = Application.FileDialog(msoFileDialogFolderPicker)
With fd
.Title = "Select the folder that contains the documents."
If .Show = -1 Then
strFolder = .SelectedItems(1) & "\"
Else
MsgBox "You did Not Select the folder that contains the documents."
Exit Sub
End If
End With
Set FSO = CreateObject("Scripting.FileSystemObject")
Set masterFolder = FSO.GetFolder(strFolder)
Set allSubfolders = masterFolder.subFolders
For Each currSubfolder In allSubfolders
Set subfolderFiles = currSubfolder.Files
For Each currFile In subfolderFiles
On Error GoTo errorProcess
leftChar = Left(currFile.Name, 1)
If leftChar <> "~" Then
Set wordDoc = Word.Documents.Open(currFile.Path)
With wordDoc
Dim SearchTerm As String, i As Long, fileName As String
Dim Rng As Range, Doc As Document, RngOut As Range
Dim searchTerms As Variant
fileName = currFile.Name
searchTerms = [removed]
For i = LBound(searchTerms) To UBound(searchTerms)
SearchTerm = searchTerms(i)
With ActiveDocument.Range
With .Find
.ClearFormatting
.Text = SearchTerm
.Forward = True
.Wrap = wdFindStop
.MatchWildcards = True
.Execute
End With
If .Find.Found Then
Dim valueFound As String
Do While .Find.Found
Set Rng = .Duplicate
valueFound = Rng.Text
nameArchive.Activate
ActiveDocument.Range(0, 0).Select
Selection.EndKey Unit:=wdStory
Selection.TypeText Text:=vbCrLf & valueFound & "," & fileName
wordDoc.Activate
.Collapse wdCollapseEnd
.Find.Execute
Loop
End If
End With
Next
End With
wordDoc.Close
End If
nextIteration:
Next currFile
Next
Dim newPath
newPath = FSO.BuildPath(masterFolder.Path, "SpecList.txt")
nameArchive.SaveAs2 fileName:=newPath, FileFormat:=wdFormatText
nameArchive.Close
wordApp.Quit
Set wordApp = Nothing
Set FSO = Nothing
valueFound = "null"
Set Rng = Nothing
Set masterFolder = Nothing
Set allSubfolders = Nothing
Set currSubfolder = Nothing
Set subfolderFiles = Nothing
Set currFile = Nothing
Exit Sub
errorProcess:
nameArchive.Activate
ActiveDocument.Range(0, 0).Select
Selection.EndKey Unit:=wdStory
If Err.Number <> 0 Then
If Not currFile Is Nothing Then
fileName = currFile.Name
Selection.TypeText Text:=vbCrLf & fileName & " " & Err.Number & " " & Err.Description
Else
Selection.TypeText Text:=vbCrLf & Err.Number & " " & Err.Description
End If
End If
Resume nextIteration
On Error GoTo 0
End Sub
Some greatly abbreviated output:
03100,03100 Concrete Formwork.docx
05501,03200 Concrete Reinforcement.docx
07920,03251 Concrete Joints.docx
03600,03300 Cast in Place Concrete.docx
~$100 Concrete Formwork.docx - 5792 The file appears to be corrupted.
~$200 Concrete Reinforcement.docx - 5792 The file appears to be corrupted.
~$251 Concrete Joints.docx - 5792 The file appears to be corrupted.
~$300 Cast in Place Concrete.docx - 5792 The file appears to be corrupted.
Any advice? Also if you see any other mistakes in the code feel free
to correct. Thank you!
~$100 Concrete Formwork.docx
~$200 Concrete Reinforcement.docx
These look like the "lock" file which Word generates when someone has a file open for editing. It's not an actual Word file, so you should maybe consider excluding any files which begin with a tilde.

VBA to find word documents and specified words in content and then list in excel

I have multiple word documents in a folder.
What I really want is to list the document names and check whether these docs incude some specified words.
I create two word documents for example to explain.
There are two documents, Doc A and Doc B, in a folder.
I want to list the file name Doc A and Doc B in the excel column A.
After listing the doc name in column A, I want to check whether specified words "classification" and "Statistics" are in the docs.
If these specified words in the document, it will mark in the excel. Please see below picture for the result I want.
I provide the code in the following:
Option Explicit
Private xRow As Long
Sub Get_MAIN_File_Names()
Dim fso As FileSystemObject
Dim xDirect As String
Dim xRootFolder As Folder
Dim DrawingNumb As String
Dim RevNumb As String
Dim rootFolderStr As String
Set fso = New FileSystemObject
xRow = 0
With Application.FileDialog(msoFileDialogFolderPicker)
.Title = "Select Main File"
.Show
'PROCESS ROOT FOLDER
If .SelectedItems.Count <> 0 Then
xDirect = .SelectedItems(1) & "\"
Set xRootFolder = fso.GetFolder(xDirect)
ProcessFolder fso, xRootFolder
End If
End With
End Sub
Private Sub ProcessFolder(fso As FileSystemObject, xFolder As Folder)
Dim xFiles As Files
Dim xFile As File
Dim xSubFolders As Folders
Dim xSubFolder As Folder
Dim xFileName As String
Dim objWordApplication As New Word.Application
Dim objWordDocument As Word.Document
Dim strFile As String
strFile = Dir(xFolder & "*.doc", vbNormal)
While strFile <> ""
With objWordApplication
Set objWordDocument = .Documents.Open(FileName:=xFolder & strFile, AddToRecentFiles:=False, ReadOnly:=True, Visible:=False)
Set xFiles = xFolder.Files
'Adding Column names
Cells(1, "A").Value = "Document Name"
Cells(1, "B").Value = "classification"
Cells(1, "C").Value = "Statistics"
'LOOPS THROUGH EACH FILE NAME IN FOLDER
For Each xFile In xFiles
'EXTRACT INFORMATION FROM FILE NAME, this part may not add
xFileName = xFile.Name
Set Docs = objWordDocument.Content
With Docs.Find
.ClearFormatting
.Text = "classification"
Wrap:=wdFindContinue
End With
With Docs.Find
.ClearFormatting
.Text = "Statistics"
Wrap:=wdFindContinue
End With
'INSERT INFO INTO EXCEL
ActiveCell.Offset(xRow, 0) = xFileName
'Below needs to add.
ActiveCell.Offset(xRow, 1) =
ActiveCell.Offset(xRow, 2) =
'Above needs to add.
xRow = xRow + 1
With objWordDocument
.Close
End With
Next xFile
Set xSubFolders = xFolder.SubFolders
For Each xSubFolder In xSubFolders
ProcessFolder fso, xSubFolder
Next xSubFolder
End Sub
Based on above code, it fails.
I think the problem is With Docs.Find.....; however, I'm not really sure about it.
Moreover, I do not know how to do this part.
'Below needs to add.
ActiveCell.Offset(xRow, 1) =
ActiveCell.Offset(xRow, 2) =
'Above needs to add.
Can any one help me edit the code?
Maybe this code will help you out, it does:
Assume you got a activesheet setup with the three headers there
Loop through .docx files in specified folder
Checks wordrange for specified tekst
Returns true or false and puts found or not found in appropriate cell
Sub LoopWordDocs()
Dim FLDR As String
Dim wDoc As Word.Document
Dim wRNG As Word.Range
Dim LR As Long, COL As Long
Dim WS As String
Dim wAPP As Word.Application
Dim WordWasNotRunning As Boolean
On Error Resume Next
Set wAPP = GetObject(, "Word.Application")
If Err Then
Set wAPP = New Word.Application
WordWasNotRunning = True
End If
On Error GoTo Err_Handler
WS = ThisWorkbook.ActiveSheet.Name
FLDR = "U:\Test\" 'Change directory accordingly
aDoc = Dir(FLDR & "*.docx") 'Change docx to .doc if you need
Do While aDoc <> ""
Set wDoc = Documents.Open(Filename:=FLDR & aDoc)
LR = Sheets(WS).Cells(Rows.Count, "A").End(xlUp).Row + 1
Sheets(WS).Cells(LR, 1) = aDoc
Set wRNG = wDoc.Range
For COL = 2 To 3 'It will loop through B1 and C1 to check if present in text
With wRNG.Find
.Text = Sheets(WS).Cells(1, COL).Text
.MatchCase = False
.MatchWholeWord = True
If wRNG.Find.Execute = True Then
Sheets(WS).Cells(LR, COL) = "V" 'Change V to your liking
Else
Sheets(WS).Cells(LR, COL) = "X" 'Change X to your liking
End If
End With
Next COL
wDoc.Close SaveChanges:=True
aDoc = Dir
Loop
Exit Sub
Err_Handler:
MsgBox "Word caused a problem. " & Err.Description, vbCritical, "Error: " & Err.Number
If WordWasNotRunning Then
wAPP.Quit
End If
End Sub
Note: You'll have to turn on Microsoft Word 14.0 Object Library for this to work

How to convert a WORD file to .txt with different header?

I have got a lot of word file (~5000) with different header what i read with a macro and merge these multiple word document placed in a folder into one document.
Here the relevant code:
Sub MergeDocs()
Dim rng As Range
Dim MainDoc As Document
Dim strFile As String, strFolder As String
Dim Count As Long
With Application.FileDialog(msoFileDialogFolderPicker)
.Title = "Pick folder"
.AllowMultiSelect = False
If .Show Then
strFolder = .SelectedItems(1) & Application.PathSeparator
Else
Exit Sub
End If
End With
Set MainDoc = Documents.Add
strFile = Dir$(strFolder & "*.doc") ' can change to .docx
Count = 0
Do Until strFile = ""
Count = Count + 1
Set rng = MainDoc.Range
With rng
.Collapse wdCollapseEnd
If Count > 1 Then
.InsertBreak wdSectionBreakNextPage
.End = MainDoc.Range.End
.Collapse wdCollapseEnd
End If
.InsertFile strFolder & strFile
End With
strFile = Dir$()
Loop
MsgBox ("Files are merged")
lbl_Exit:
Exit Sub
End Sub
It is working, but when I am trying to save file as .txt, the header+footer lose..is it any way which one I can save this header part to a .txt file too? (as I wrote, in every document has got different header.)
EDIT:
Sub MergeDocs()
Dim rng As Range
Dim MainDoc As Document
Dim strFile As String, strFolder As String
Dim Count As Long
With Application.FileDialog(msoFileDialogFolderPicker)
.Title = "Pick folder"
.AllowMultiSelect = False
If .Show Then
strFolder = .SelectedItems(1) & Application.PathSeparator
Else
Exit Sub
End If
End With
Set MainDoc = Documents.Add
strFile = Dir$(strFolder & "*.doc") ' can change to .docx
Count = 0
Dim doc As Document
Dim head As String, foot As String
Do Until strFile = ""
Set doc = Documents.Open(strFile)
head = doc.Sections(1).Headers(wdHeaderFooterPrimary).Range.Text
foot = doc.Sections(1).Footers(wdHeaderFooterPrimary).Range.Text
doc.Close False
Count = Count + 1
Set rng = MainDoc.Range
With rng
.Collapse wdCollapseEnd
If Count > 1 Then
.InsertBreak wdSectionBreakNextPage
.End = MainDoc.Range.End
.Collapse wdCollapseEnd
End If
.InsertAfter head
.InsertParagraphAfter
.InsertFile strFolder & strFile
.InsertAfter foot
End With
strFile = Dir$()
Loop
MsgBox ("Files are merged")
lbl_Exit:
Exit Sub
End Sub
This is not fully tested but should get you going.
I have only altered your Do loop. Replace, try out and have fun:
Dim doc As Document
Dim head As String, foot As String
Do Until strFile = ""
Set doc = Documents.Open(strFolder & strFile)
head = doc.Sections(1).Headers(wdHeaderFooterPrimary).Range.text
foot = doc.Sections(1).Footers(wdHeaderFooterPrimary).Range.text
doc.Close False
Count = Count + 1
Set rng = MainDoc.Range
With rng
.Collapse wdCollapseEnd
If Count > 1 Then
.InsertBreak wdSectionBreakNextPage
.End = MainDoc.Range.End
.Collapse wdCollapseEnd
End If
.InsertAfter head
.InsertParagraphAfter
.InsertFile strFolder & strFile
.InsertAfter foot
End With
strFile = Dir$()
Loop