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

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

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

How to loop through files in a folder?

I'm attempting to Loop my Dir subroutine rather than copying the code all over again.
The code prompts a user for a search word.
A count is given in the document. Black (1 time), red (2 times), or bolded red (3+ times).
Images in the file are doubled in size. If there are no images a MsgBox says "no images in file".
To modify multiple documents with this program, I need to input a directory (Dir) and then loop through the files of the directory.
Sub austinolson()
Dim WordInput As String
Dim WordCount As Integer
Dim Range As word.Range
WordInput = InputBox("Search for a word")
'Everything below this code
Set Range = ActiveDocument.Content
WordCount = 0
With Range.Find
.ClearFormatting
.Format = False
.Forward = True
.MatchWholeWord = True
.Text = WordInput
.Wrap = wdFindStop
.Execute
Do While .Found
WordCount = WordCount + 1
Range.Collapse word.WdCollapseDirection.wdCollapseEnd
.Execute
Loop
End With
MsgBox ("The word: '" & "" & WordInput & "" & "' shows up " & WordCount & " times in the document")
ActiveDocument.Content.InsertParagraphAfter
Set Range = ActiveDocument.Content
Range.Collapse word.WdCollapseDirection.wdCollapseEnd
Range.Text = "Number occurrences: " & WordCount
If WordCount >= 3 Then
Range.Font.ColorIndex = wdRed
Range.Font.Bold = True
ElseIf WordCount >= 2 Then
Range.Font.ColorIndex = wdRed
Range.Font.Bold = False
Else
Range.Font.ColorIndex = wdBlack
Range.Font.Bold = False
End If
'Inline shape count below'
Dim h As Long
Dim w As Long
Dim rng As Range
Dim Ishape As InlineShape
Set rng = ActiveDocument.Content
If rng.InlineShapes.Count = 0 Then
MsgBox "No images to modify"
End If
For Each Ishape In ActiveDocument.InlineShapes
h = Ishape.Height
w = Ishape.Width
Ishape.Height = 2 * h
Ishape.Height = 2 * w
Next Ishape
'location input:
Dim Path As String
Dim currentFilename As String
currentFilename = ""
Path = ""
Do While (Path = "")
Path = InputBox("Location of documents e.g. C:\203\: ")
If (Path = "") Then
MsgBox ("No location entered, ending program")
Exit Sub
End If
Loop
'Everything above this code:
currentFilename = Dir(Path & "*.docx")
Do While (currentFilename <> "")
MsgBox (currentFilename)
If (currentFilename <> "") Then
Documents.Open (Path & currentFilename)
'
' Need to apply loop inbetween "Above and below code" HERE to the opened word documents.
'
ActiveDocument.Close (wdSaveChanges)
End If
currentFilename = Dir
Loop
End Sub
Here's what I mean - your main Sub gets user input and loops over the files, but the other tasks are split out into discrete Subs/Functions.
Compiled, but not tested, so you may need to fix some things...
Sub MainProgram()
Dim WordInput As String
Dim WordCount As Long, ImageCount As Long
Dim doc As Document
Dim Path As String
Dim currentFilename As String
currentFilename = ""
'get a path from the user
Path = Trim(InputBox("Location of documents e.g. 'C:\203\'"))
If Path = "" Then
MsgBox "No location entered, ending program"
Exit Sub
End If
If Right(Path, 1) <> "\" Then Path = Path & "\" 'ensure trailing slash
'get the search word
WordInput = Trim(InputBox("Search for a word"))
If Len(WordInput) = 0 Then Exit Sub 'maybe add a message here...
'start looping over the folder
currentFilename = Dir(Path & "*.docx")
Do While currentFilename <> ""
Set doc = Documents.Open(Path & currentFilename)
WordCount = CountTheWord(doc, WordInput) 'count the words
TagWordCount doc, WordInput, WordCount 'insert count to doc
ImageCount = ResizeInlineShapes(doc)
Debug.Print "'" & WordInput & "' shows up " & WordCount & " times in '" & doc.Name & "'"
Debug.Print "...and there were " & ImageCount & " images resized"
doc.Close wdSaveChanges
currentFilename = Dir
Loop
End Sub
Function CountTheWord(doc As Document, theWord As String) As Long
Dim WordCount As Long, rng As Range
Set rng = doc.Content
WordCount = 0
With rng.Find
.ClearFormatting
.Format = False
.Forward = True
.MatchWholeWord = True
.Text = theWord
.Wrap = wdFindStop
.Execute
Do While .Found
WordCount = WordCount + 1
rng.Collapse wdCollapseEnd
.Execute
Loop
End With
CountTheWord = WordCount
End Function
'append a word count to the end of the document
Sub TagWordCount(doc As Document, theWord As String, theCount As Long)
Dim rng As Range
doc.Content.InsertParagraphAfter
Set rng = doc.Content
rng.Collapse wdCollapseEnd
rng.Text = "Number occurrences for '" & theWord & "': " & theCount
rng.Font.Bold = (theCount >= 3)
rng.Font.ColorIndex = IIf(theCount >= 2, wdRed, wdBlack)
End Sub
Function ResizeInlineShapes(doc As Document) As Long
Dim rv As Long, Ishape As InlineShape
For Each Ishape In doc.InlineShapes
Ishape.Height = 2 * Ishape.Height
Ishape.Height = 2 * Ishape.Height
rv = rv + 1
Next Ishape
ResizeInlineShapes = rv '<< number of shapes resized
End Function

Find and Replace VB Macro

I am using a Find and Replace script/macro in MS Word. For the two lines below, how would I adjust this to be case sensitive? Right now it will replace us, bus, ect..
Const strFind As String = "US"
Const strRepl As String = "USA"
Sub BatchProcess()
Dim strFileName As String
Dim strPath As String
Dim oDoc As Document
Dim fDialog As FileDialog
Dim oStory As Range
Dim oRng As Range
Const strFind As String = "2017"
Const strRepl As String = "2018"
Set fDialog = Application.FileDialog(msoFileDialogFolderPicker)
With fDialog
.Title = "Select folder and click OK"
.AllowMultiSelect = False
.InitialView = msoFileDialogViewList
If .Show <> -1 Then
MsgBox "Cancelled By User", , _
"List Folder Contents"
Exit Sub
End If
strPath = fDialog.SelectedItems.Item(1) & "\"
End With
strFileName = Dir$(strPath & "*.docx")
While Len(strFileName) <> 0
WordBasic.DisableAutoMacros 1
Set oDoc = Documents.Open(strPath & strFileName)
For Each oStory In ActiveDocument.StoryRanges
Set oRng = oStory
With oRng.Find
Do While .Execute(FindText:=strFind)
oRng.Text = strRepl
oRng.Collapse wdCollapseEnd
Loop
End With
If oStory.StoryType <> wdMainTextStory Then
While Not (oStory.NextStoryRange Is Nothing)
Set oStory = oStory.NextStoryRange
Set oRng = oStory
With oRng.Find
Do While .Execute(FindText:=strFind)
oRng.Text = strRepl
oRng.Collapse wdCollapseEnd
Loop
End With
Wend
End If
Next oStory
oDoc.SaveAs FileName:=strPath & strFileName
oDoc.Close SaveChanges:=wdDoNotSaveChanges
strFileName = Dir$()
WordBasic.DisableAutoMacros 0
Wend
Set oDoc = Nothing
Set oStory = Nothing
Set oRng = Nothing
End Sub
In response to the post below. I have added the entire code.
The Find and Replace method has a boolean MatchCase property. Set it to True.
Example: In your DoWhile code. Do While .Execute(FindText:=strFind, MatchCase:=True)
Simply matching the case is insufficient if what you're searching for as a whole word might also exist within a larger string. Try:
Sub BatchProcess()
Application.ScreenUpdating = False
Dim strFileName As String, strPath As String
Dim oDoc As Document, oStory As Range
Dim fDialog As FileDialog
Set fDialog = Application.FileDialog(msoFileDialogFolderPicker)
With fDialog
.Title = "Select folder and click OK"
.AllowMultiSelect = False
.InitialView = msoFileDialogViewList
If .Show <> -1 Then
MsgBox "Cancelled By User", , "List Folder Contents"
Exit Sub
End If
strPath = fDialog.SelectedItems.Item(1) & "\"
End With
strFileName = Dir$(strPath & "*.docx")
WordBasic.DisableAutoMacros 1
While Len(strFileName) <> 0
Set oDoc = Documents.Open(strPath & strFileName)
With oDoc
For Each oStory In .StoryRanges
While Not (oStory Is Nothing)
oStory.Find.Execute FindText:="<US>", Replacewith:="USA", Forward:=True, _
Wrap:=wdFindContinue, MatchWildcards:=True, Replace:=wdReplaceAll
Set oStory = oStory.NextStoryRange
Wend
Next oStory
.SaveAs FileName:=strPath & strFileName
.Close SaveChanges:=wdDoNotSaveChanges
End With
strFileName = Dir$()
Wend
WordBasic.DisableAutoMacros 0
Set oDoc = Nothing: Set oStory = Nothing
Application.ScreenUpdating = True
End Sub
Note that I've used wildcards, combined with as the Find expression. That guarantees only whole upper-case words will be matched. you could achieve the same with:
oStory.Find.Execute FindText:="US", Replacewith:="USA", Forward:=True, _
Wrap:=wdFindContinue, MatchWholeWord:=True, MatchCase:=True, Replace:=wdReplaceAll
Note, too, the overall simplification of your code.

Do a simple calculation in word using 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