I have found many examples of macros to copy selected pages to a new document, however, I am unable to find any examples of macros that use find and replace to locate a word, and copy the entire page containing that word to a new word document or notepad.
Sub PageGrabber()
Dim doc As Word.Document, rng As Word.Range
On Error GoTo ERRORHANDLER
Set doc = ActiveDocument
Set rng = doc.Content
Set rng = doc.Content
With rng.Find
.Text = "help"
.Replacement.Text = " "
.MatchWildcards = False
.Wrap = wdFindStop
.Format = False
.Forward = True
While .Execute
ActiveDocument.Bookmarks("\page").Range.Copy
Documents.Open FileName:="C:\test.docx"
Selection.Paste
rng.Collapse Word.WdCollapseDirection.wdCollapseEnd
Wend
End With
ERRORHANDLER:
If Err.Number <> 0 Then
MsgBox Err.Number & vbCr & Err.Description, vbCritical
Err.Clear
Else
MsgBox "Action Complete"
End If
End Sub
I was attempting to use while .execute during the find to then grab the ActiveDocument.Bookmarks("\page").Range.Copy object and paste it onto a seperate document, it resulted in the first page being copied and nothing else.
If anyone has a link to an example or some useful advice to get this to happen it would be appreciated, thanks.
For example:
Sub PageGrabber()
Application.ScreenUpdating = False
Dim DocSrc As Document, DocTgt As Document
Set DocSrc = ActiveDocument
With DocSrc.Range
With .Find
.Text = "help"
.Replacement.Text = " "
.MatchWildcards = False
.Wrap = wdFindStop
.Format = False
.Forward = True
.Execute
End With
If .Find.Found = True Then
Set DocTgt = Documents.Open(FileName:="C:\test.docx", AddToRecentFiles:=False, Visible:=False)
DocTgt.Range.FormattedText = .Bookmarks("\page").Range.FormattedText
DocTgt.Close True
End If
End With
Set DocTgt = Nothing: Set DocSrc = Nothing
Application.ScreenUpdating = True
End Sub
Related
I would like to apply a VBA Macro to multiple docx files. My macro find a text with a specific font and then hide it.
This is the macro that works when you execute it on a single docx file :
Sub color()
Dim Rng As Range
Dim Fnd As Boolean
G:
Set Rng = ActiveDocument.Range
Rng.Find.ClearFormatting
Rng.Find.Font.color = RGB(191, 191, 191)
Rng.Find.Replacement.ClearFormatting
With Rng.Find
.Text = ""
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindContinue
.Format = True
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
.Execute
Fnd = .Found
End With
If Fnd = True Then
With Rng
.MoveStart wdWord, 0
.Select
With .Font
.Hidden = True
End With
End With
GoTo G
End If
End Sub
And I've found a macro on a forum that can loop on all files in a folder and I've combined to mine :
Sub Documentos()
Application.ScreenUpdating = False
Dim strFolder As String, strFile As String, strDocNm As String, wdDoc As Document
strDocNm = ActiveDocument.FullName: strFolder = GetFolder
If strFolder = "" Then Exit Sub
strFile = Dir(strFolder & "\*.docx", vbNormal)
While strFile <> ""
If strFolder & "\" & strFile <> strDocNm Then
Set wdDoc = Documents.Open(FileName:=strFolder & "\" & strFile, AddToRecentFiles:=False, Visible:=False)
With wdDoc
Dim Rng As Range
Dim Fnd As Boolean
G:
Set Rng = ActiveDocument.Range
Rng.Find.ClearFormatting
Rng.Find.Font.color = RGB(191, 191, 191)
Rng.Find.Replacement.ClearFormatting
With Rng.Find
.Text = ""
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindContinue
.Format = True
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
.Execute
Fnd = .Found
End With
If Fnd = True Then
With Rng
.MoveStart wdWord, 0
.Select
With .Font
.Hidden = True
End With
End With
GoTo G
End If
.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
When I execute this macro, I opens the document but does nothing.
Can someone help to combine them ?
I guess it's because of Set Rng = ActiveDocument.Range. in the loop you set Rng to active document. open a file doesn't make it activated automatically. And I see you have already assigned the opened file to wdDoc. Maybe use 'Set Rng = .Range' instead. see if it works for you.
Use the tools already built into Word.
A much simpler route to do that same effect is to create a Word character style with gray shading and apply that to all text that is to have a grey background. Then you can change all instances to a clear background by simply changing the style definition:
Sub ChangeShadedTextStyle()
ActiveDocument.Styles("Shaded Text").Font.Shading.BackgroundPatternColor = wdColorAutomatic
End Sub
I have almost 1,800 Word documents that have about 8 pages with unique data in tables. We were just informed that the data we were given for some of those tables is inaccurate and needs to be changed from "N/A" to "0.0%". As "N/A" is used a lot in the document, I unfortunately cannot just find/replace that text.
Using this thread (Macro to find in Word table for specific string in a cell and move x cell left, check isnumeric then set typography on down x cell in the same column) I was able to adjust the code below to find the column header (On-Time Completion Rate) and move to the adjacent cells to update them. However, since this column is for percentages, the IsNumeric code is changing any data it finds due to the percentage symbol.
Is there a way to do the same but instead of using IsNumeric (since it does not work for percentages) check the value in the cell and if it finds "N/A" change it to "0.0%"? This would then need to be repeated for two more tables, with one table have four rows to look through.
Thank you in advance for any help you can offer!
Screenshot of table
Sub Demo()
Application.ScreenUpdating = False
Dim r As Long, c As Long
With ActiveDocument.Range
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = "On-time Completion Rate" 'Column Header'
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindStop
.Format = False
.MatchWildcards = True
.Execute
End With
Do While .Find.Found
If .Information(wdWithInTable) = True Then
r = .Cells(1).RowIndex
c = .Cells(1).ColumnIndex
With .Tables(1)
If Not IsNumeric(Split(.Cell(r + 1, c).Range.Text, vbCr)(0)) Then .Cell(r + 1, c).Range.Text = "0.0%"
If Not IsNumeric(Split(.Cell(r + 2, c).Range.Text, vbCr)(0)) Then .Cell(r + 2, c).Range.Text = "0.0%"
End With
End If
.Collapse wdCollapseEnd
.Find.Execute
Loop
End With
Application.ScreenUpdating = True
End Sub
Try this:
Sub Demo()
Application.ScreenUpdating = False
Dim r As Long, c As Long
With ActiveDocument.Range
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = "On-time Completion Rate" 'Column Header'
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindStop
.Format = False
.MatchWildcards = True
.Execute
End With
Do While .Find.Found
If .Information(wdWithInTable) = True Then
r = .Cells(1).RowIndex
c = .Cells(1).ColumnIndex
With .Tables(1)
If Split(.Cell(r + 1, c).Range.Text, vbCr)(0) = "N/A" Then .Cell(r + 1, c).Range.Text = "0.0%"
If Split(.Cell(r + 2, c).Range.Text, vbCr)(0) = "N/A" Then .Cell(r + 2, c).Range.Text = "0.0%"
End With
End If
.Collapse wdCollapseEnd
.Find.Execute
Loop
End With
Application.ScreenUpdating = True
End Sub
If all instances of N/A in the tables are to be replaced, the following would be more efficient:
Sub Demo()
Application.ScreenUpdating = False
With ActiveDocument.Range
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = "On-time Completion Rate"
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindStop
.Format = False
.MatchWildcards = True
.Execute
End With
Do While .Find.Found
.Duplicate.Tables(1).Range.Find.Execute FindText:="N/A", ReplaceWith:="0.0%", Wrap:=wdFindStop, Replace:=wdReplaceAll
.Collapse wdCollapseEnd
.Find.Execute
Loop
End With
Application.ScreenUpdating = True
End Sub
Extending this to process a whole folder of documents, you could use code like:
Sub UpdateDocuments()
Application.ScreenUpdating = False
Dim strFolder As String, strFile As String, strDocNm As String, wdDoc As Document
strDocNm = ActiveDocument.FullName: strFolder = GetFolder
If strFolder = "" Then Exit Sub
strFile = Dir(strFolder & "\*.docx", vbNormal)
While strFile <> ""
If strFolder & "\" & strFile <> strDocNm Then
Set wdDoc = Documents.Open(FileName:=strFolder & "\" & strFile, AddToRecentFiles:=False, Visible:=False)
With wdDoc
With .Range
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = "On-time Completion Rate"
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindStop
.Format = False
.MatchWildcards = True
.Execute
End With
Do While .Find.Found
.Duplicate.Tables(1).Range.Find.Execute FindText:="N/A", ReplaceWith:="0.0%", Wrap:=wdFindStop, Replace:=wdReplaceAll
.Collapse wdCollapseEnd
.Find.Execute
Loop
End With
.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
To extend the code even further to process documents in sub-folders, see: https://www.msofficeforums.com/47785-post14.html
To save the updated documents as PDFs, insert:
.SaveAs FileName:=Split(.FullName, ".doc")(0) & ".pdf", FileFormat:=wdFormatPDF, AddToRecentFiles:=False
before:
.Close SaveChanges:=True
I am trying to create an audiobook with multiple tracks so it's easy to navigate through the book while I'm doing other things like driving or working out. The only way I can think to do this is to have each heading and its contents in its own separate document. I've been using the select headings and content option but there's no shortcut for this option. you must click it each time.
everything I've looked at online doesn't do what I want.
is there a way to select each heading and contents copy that to a new document, save it as TXT so each of the heading and content is in its own document?
Select Heading and Content
You could use a macro like the following to split the document at the Heading1 level:
Sub SplitDocumentByHeading()
Application.ScreenUpdating = False
Dim DocSrc As Document, DocTgt As Document, Rng As Range, i As Long
Dim StrTmplt As String, StrNm As String, StrEx As String, lFmt As Long
Set DocSrc = ActiveDocument
With DocSrc
StrTmplt = .AttachedTemplate.FullName
StrNm = Split(.FullName, ".doc")(0)
StrEx = Split(.FullName, ".doc")(1)
lFmt = .SaveFormat
With .Range
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = ""
.Style = wdStyleHeading1
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindStop
.Format = True
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
.Execute
End With
Do While .Find.Found
i = i + 1
Set Rng = .Duplicate.GoTo(What:=wdGoToBookmark, Name:="\HeadingLevel")
Set DocTgt = Documents.Add(Template:=StrTmplt, Visible:=False)
With DocTgt
.Range.FormattedText = Rng.FormattedText
.SaveAs2 FileName:=StrNm & "_" & Format(i, "00") & ".txt", Fileformat:=wdFormatText, AddToRecentFiles:=False
.Close
End With
.Collapse wdCollapseEnd
.Find.Execute
Loop
End With
End With
Set DocTgt = Nothing: Set Rng = Nothing: Set DocSrc = Nothing
Application.ScreenUpdating = True
End Sub
Rather more complex code would be required to split it at the sub-heading level.
We are trying to revise rtf docs that are created by Molecular Device software.
Here is an example of part of one of these documents:
Protocol 'C:\ALL USERS\Params\Current\2017 Opto Params\0 VoltageClampContinuous.pro' opened.
C:\ALL USERS\Alan\2018_07_11\2018_07_11_0000.abf started at 00:19:48 stopwatch time.
So for right now - all I am trying to do is automatically find the experiment date (in this case = "2018_07_11_")
My sub so far can find the correct cursor positions but how do I select the text between 2 cursor positions?
Below is what I have the CursorPosition statement is of course wrong - this is what I am looking to correct.
Sub FindfilenameDate()
txt_prior_to_expDate = "\"
txt_after_expDate = "0000"
With ActiveDocument.Content.Find
.Text = txt_after_expDate
.Forward = True
.Execute
If .Found = True Then
.Parent.Select
Set after_rng = Selection.Range
expDateEnd_cursorPos = after_rng.Start - 1
Selection.HomeKey Unit:=wdStory, Extend:=wdExtend
With Selection.Find
.Text = txt_prior_to_expDate
.Forward = False
.Execute
If .Found = True Then
.Parent.Select
Set charBefore_expDate = Selection.Range
expDateStart_cursorPos = charBefore_expDate.Start + 1
End If
End With
End If
End With
'expDate = CursorPosition(expDateStart_cursorPos, expDateEnd_cursorPos)
'MsgBox ("expDate = " & expDate) 'DELETEMSGBOX
End Sub
The trick to something like this is to work with multiple Range objects. My personal preference is to declare a Range for each separate thing to be worked with, rather than trying to figure out the minimum and re-use a Range - at least for the initial code and testing purposes.
For this task, then, I use four Ranges: 1) For the original search, 2) for the end of the "cursor position" that's wanted, 3) For the second search, 4) for the final "cursor position".
The other important concepts are how to "collapse" a Range and how to "copy" one.
Collapsing a Range is like pressing the right- or left-arrow key with a selection, so that it is a "point" and doesn't contain anything. A Range can be collapsed to its start or end position.
Copying a Range (setting one Range to another) needs to be done using the Duplicate property so that the copy is independent of the original. Otherwise, when one is changed the other changes, as well.
Sub FindfilenameDate()
Dim rngFind As Word.Range, rngBefore As Word.Range
Dim rngAfter As Word.Range, rngFound As Word.Range
txt_prior_to_expDate = "\"
txt_after_expDate = "0000"
Set rngFind = ActiveDocument.content
With rngFind.Find
.Text = txt_after_expDate
.Forward = True
.Execute
If .found = True Then
Set rngAfter = rngFind.Duplicate
rngAfter.Collapse wdCollapseStart
Set rngBefore = rngFind.Duplicate
rngBefore.Collapse wdCollapseStart
With rngBefore.Find
.Text = txt_prior_to_expDate
.Forward = False
.Execute
If .found = True Then
Set rngFound = rngBefore.Duplicate
rngFound.Collapse wdCollapseEnd
rngFound.End = rngAfter.Start
'rngFound.Select
End If
End With
End If
End With
'expDate = CursorPosition(expDateStart_cursorPos, expDateEnd_cursorPos)
MsgBox ("expDate = " & rngFound.Text) 'DELETEMSGBOX
End Sub
Though it's not apparent why you're after the date string ending in _0000 rather than the date that is the parent folder name, a much simpler approach for a single date would be:
Sub Demo()
Application.ScreenUpdating = False
With ActiveDocument.Range
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = "[0-9]{4}_[0-9]{2}_[0-9]{2}_0000"
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindStop
.Format = False
.MatchWildcards = True
.Execute
End With
If .Find.Found = True Then MsgBox "expDate = " & Split(.Text, "_0000")(0)
End With
Application.ScreenUpdating = True
End Sub
And, for all such dates in a document:
Sub Demo()
Application.ScreenUpdating = False
With ActiveDocument.Range
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = "[0-9]{4}_[0-9]{2}_[0-9]{2}_0000"
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindStop
.Format = False
.MatchWildcards = True
.Execute
End With
Do While .Find.Found = True
MsgBox "expDate = " & Split(.Text, "_0000")(0)
.Collapse wdCollapseEnd
.Find.Execute
Loop
End With
Application.ScreenUpdating = True
End Sub
I am writing a script that extract tables from Word file as copies it to a worksheet in Excel. However, the Word files I received do not have the same format and the tables I need are not always on the same page. Hence I cannot use the regular table index.
Each table is on a different page and only on that page there somewhere is a text string (may or may not be in the table itself) like 'material/material list'. What I'd like to do is scan each page of the Word document for a certain textstring and only if that string is present, use the corresponding table on that page. Is this possible and how would I go about this?
A complication of the inconsistent formatting is that on some pages, the data is not even in a table so for those files I'd like an alert if the trigger word is found on a page but no table is there.
Edited:
I have tried to redefine the range considered. My hope is that this is the easiest method; see where the keyword occurs and then use the first table after that. However this does not seem to work.
With ActiveDocument.Content.Find
.Text = "Equipment"
.Forward = True
.Execute
If .Found = True Then Set aRange = ActiveDocument.Range(Start:=0, End:=0)
End With
Edit:
I tried to combine the code from macropod with a vba in Excel that copies the table to the worksheet.
Sub LookForWordDocs()
Dim FolderName As String
With Application.FileDialog(msoFileDialogFolderPicker)
.AllowMultiSelect = False
.Show
On Error Resume Next
FolderName = .SelectedItems(1)
Err.Clear
On Error GoTo 0
End With
Dim sFoldPath As String: sFoldPath = FolderName ' Change the path. Ensure that your have "\" at the end of your path
Dim oFSO As New FileSystemObject ' Requires "Microsoft Scripting Runtime" reference
Dim oFile As File
' Loop to go through all files in specified folder
For Each oFile In oFSO.GetFolder(sFoldPath).Files
' Check if file is a word document. (Also added a check to ensure that we don't pick up a temp Word file)
If ((InStr(1, LCase(oFSO.GetExtensionName(oFile.Path)), "doc", vbTextCompare) > 0) Or _
(InStr(1, LCase(oFSO.GetExtensionName(oFile.Path)), "docx", vbTextCompare) > 0)) And _
(InStr(1, oFile.Name, "~$") = 0) And _
((InStr(1, oFile.Name, "k") = 1) Or (InStr(1, oFile.Name, "K") = 1)) Then
' Call the UDF to copy from word document
ImpTable oFile
End If
Next
End Sub
Sub ImpTable(ByVal oFile As File)
Dim oWdApp As New Word.Application
Dim oWdDoc As Word.Document
Dim oWdTable As Word.Table
Dim oWS As Excel.Worksheet
Dim lLastRow$, lLastColumn$
Dim s As String
s = "No correct table found"
With Excel.ThisWorkbook
Set oWS = Excel.Worksheets.Add
On Error Resume Next
oWS.Name = oFile.Name
On Error GoTo 0
Set sht = oWS.Range("A1")
Set oWdDoc = oWdApp.Documents.Open(oFile.Path)
oWdDoc.Activate
'Application.ScreenUpdating = False
Dim StrFnd As String, Rng As Word.Range, i As Long, j As Long
j = 0
StrFnd = "equipment"
With ActiveDocument.Range
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = StrFnd
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindStop
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
.Execute
End With
Do While .Find.Found
i = .Information(wdActiveEndAdjustedPageNumber)
Set Rng = Word.ActiveDocument.Goto(What:=wdGoToPage, Name:=i)
Set Rng = Rng.Goto(What:=wdGoToBookmark, Name:="\page")
If Rng.Tables.Count > 0 Then
With Rng.Tables(1)
Set oWdTable = Rng.Tables(1)
oWdTable.Range.Copy
sht.PasteSpecial xlPasteValues, xlPasteSpecialOperationNone
j = 1
End With
End If
.Start = Rng.End
.Find.Execute
Loop
End With
If j = 0 Then sht.Value = s
'Application.ScreenUpdating = True
oWdDoc.Close savechanges:=False
oWdApp.Quit
End With
Set oWS = Nothing
Set sht = Nothing
Set oWdDoc = Nothing
Set oWdTable = Nothing
Set Rng = Nothing
End Sub
For the first file, the code works fine. However on the second run I get a run-time error "The remote Server Machine does not Exist or is unavailable" on line
"Word.ActiveDocument.Range". I added a couple of qualifications for elements but this still did not solve the problem. Am I missing another line?
BTW When I place "Word" before ActiveDocument.Range the code does not work any more.
Since you've changed the text from 'material/material list' to 'Equipment', it's a bit hard to know quite what you want. Try something along the lines of:
Sub Demo()
Application.ScreenUpdating = False
Dim StrFnd As String, Rng As Range, i As Long
StrFnd = InputBox("What is the Text to Find")
If Trim(StrFnd) = "" Then Exit Sub
With ActiveDocument.Range
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = StrFnd
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindStop
.Format = False
.MatchCase = True
.MatchWholeWord = True
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
.Execute
End With
Do While .Find.Found
i = .Information(wdActiveEndAdjustedPageNumber)
Set Rng = ActiveDocument.GoTo(What:=wdGoToPage, Name:=i)
Set Rng = Rng.GoTo(What:=wdGoToBookmark, Name:="\page")
If Rng.Tables.Count > 0 Then
MsgBox Chr(34) & StrFnd & Chr(34) & " and table found on page " & i & "."
With Rng.Tables(1)
'process this table
End With
Else
MsgBox Chr(34) & StrFnd & Chr(34) & " found on page " & i & " but no table."
End If
.Start = Rng.End
.Find.Execute
Loop
End With
Application.ScreenUpdating = True
End Sub
Note: the above code will test all pages on which the Find text is found.