Find text section and insert into table - vba

everyone.
I've only been immersed in the world of macros for a few days now and don't really know my way around.
I have several Word 2016 documents that I want to reformat. Each document has exactly the same structure (see attached file).
What I have done so far (and how it works)
Since the images are distorted and too large, I first set them in the same aspect ratio and reduce them to 50%.
Dim i As Long
With ActiveDocument
For i = 1 To .InlineShapes.Count
With .InlineShapes(i)
.ScaleHeight = 50
.ScaleWidth = 50
End With
Next i
End With
Then I search for the text lines "Slide notes" and replace them with the text "Speaker text:".
And also the text "Text Captions" I replace in the same way, with "Screen text:"
Set myRange = ActiveDocument.Content
myRange.Find.Execute FindText:="Slide notes", _
ReplaceWith:="Speaker text:", Replace:=wdReplaceAll
Set myRange = ActiveDocument.Content
myRange.Find.Execute FindText:="Text Captions", _
ReplaceWith:="Screen text:", Replace:=wdReplaceAll
And now I just can't get any further
Next, on each page, the text between "Speaker text" and "Screen text" should be filled into a table with two columns.
Ideally, the two columns should have a division of 2/3 to 1/3 (at full width).
At each line break, a new table line should be inserted
The table should end with the last entry (before "Screen text:")
This is the script, how I try to create the two-column table but unfortunately not working correctly.
Dim rng As Range
sTx = "Speaker text:"
With ActiveDocument
Set rng = .Range(.Characters(InStr(.Content, sTx) + Len(sTx) + 1).Start, .Characters(InStr(.Content, "Screen text:") - 1).End)
rng.Select
rng.ConvertToTable Separator:=wdSeparateByParagraphs, NumColumns:=1, _
NumRows:=2, InitialColumnWidth:=CentimetersToPoints(5), AutoFitBehavior _
:=wdAutoFitFixed
With rng.Tables(1)
.ApplyStyleHeadingRows = True
.ApplyStyleLastRow = False
.ApplyStyleFirstColumn = True
.ApplyStyleLastColumn = False
'Apply borders around table
.Borders(wdBorderTop).LineStyle = wdLineStyleSingle
.Borders(wdBorderBottom).LineStyle = wdLineStyleSingle
.Borders(wdBorderLeft).LineStyle = wdLineStyleSingle
.Borders(wdBorderRight).LineStyle = wdLineStyleSingle
End With
.Tables(1).Range.Columns.Add ' InsertColumnsRight
.Tables(1).Columns(1).SetWidth ColumnWidth:=184.05, RulerStyle:= _
wdAdjustFirstColumn
.Tables(1).Columns(2).SetWidth ColumnWidth:=99.2, RulerStyle:= _
wdAdjustFirstColumn
End With
Unfortunately, it doesn't work the way I want it to.
Only one table is created (on the first page)
Only one frame is visible (no subdivision)
There is always an empty row (table)
The table does not have the full widthe
Before / After

Try:
Sub Demo()
Application.ScreenUpdating = False
Dim i As Long
With ActiveDocument.Range
For i = 1 To .InlineShapes.Count
With .InlineShapes(i)
.ScaleHeight = 50
.ScaleWidth = 50
End With
Next i
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = "Slide notes*Text Captions"
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindStop
.Format = False
.MatchWildcards = True
End With
Do While .Find.Execute
.Paragraphs.First.Range.Text = "Speaker text:"
.Paragraphs.Last.Range.Text = "Screen text:" & vbCr
.Start = .Paragraphs.First.Range.End
.End = .Paragraphs.Last.Range.Start
Do While .Characters.First.Text = vbCr
.Characters.First.Delete
Loop
With .Duplicate
.Find.Execute FindText:="^13^13", ReplaceWith:="^t^p", Replace:=wdReplaceAll
.ConvertToTable Separator:=vbTab, NumRows:=.Paragraphs.Count, NumColumns:=2, AutoFitBehavior:=wdAutoFitWindow
With .Tables(1)
.AllowAutoFit = False
.PreferredWidthType = wdPreferredWidthPoints
.Borders.Enable = True
.Rows(1).HeadingFormat = True
.Columns(1).SetWidth ColumnWidth:=.PreferredWidth * 2 / 3, RulerStyle:=wdAdjustProportional
Do While .Range.Characters.Last.Next = vbCr
.Range.Characters.Last.Next.Delete
Loop
End With
End With
.Collapse wdCollapseEnd
Loop
End With
Application.ScreenUpdating = True
End Sub

#macropod
May I ask you to explain your script to me.
The first part (the proportional reduction of the images) is clear so far.
Application.ScreenUpdating = False
Dim i As Long
With ActiveDocument.Range
For i = 1 To .InlineShapes.Count
With .InlineShapes(i)
.ScaleHeight = 50
.ScaleWidth = 50
End With
With the second section (replacing the two phrases), I already have more problems.
Next i
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = "Slide notes*Text Captions"
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindStop
.Format = False
.MatchWildcards = True
End With
Do While .Find.Execute
.Paragraphs.First.Range.Text = "Speaker text:"
.Paragraphs.Last.Range.Text = "Screen text:" & vbCr
.Start = .Paragraphs.First.Range.End
.End = .Paragraphs.Last.Range.Start
Do While .Characters.First.Text = vbCr
.Characters.First.Delete
Loop
And I am hopelessly overwhelmed with the last part.
With .Duplicate
.Find.Execute FindText:="^13^13", ReplaceWith:="^t^p", Replace:=wdReplaceAll
.ConvertToTable Separator:=vbTab, NumRows:=.Paragraphs.Count, NumColumns:=2, AutoFitBehavior:=wdAutoFitWindow
With .Tables(1)
.AllowAutoFit = False
.PreferredWidthType = wdPreferredWidthPoints
.Borders.Enable = True
.Rows(1).HeadingFormat = True
.Columns(1).SetWidth ColumnWidth:=.PreferredWidth * 2 / 3, RulerStyle:=wdAdjustProportional
Do While .Range.Characters.Last.Next = vbCr
.Range.Characters.Last.Next.Delete
Loop
End With
End With
.Collapse wdCollapseEnd
Loop
End With
Application.ScreenUpdating = True
Please excuse me for inquiring. But I would like to understand the script.
Because I would also like to rewrite the script so that I can use it without the "Screen text:" section.
Thank you very much and best regards.

Related

Remove OR replace faulty paragraph marks using VBA macro

I have some faulty paragraphs, which are causing my other macros to not work properly.
They are usually heading style 2, style 3
Empty (not sure)
before OR after table (not sure)
surrounded by dotted line
causes the heading and next table to merged together (not sure)
I tried to replace/removed those with the following macro:
Sub HeadingParaBug()
Dim H As Range
Set H = ActiveDocument.Range
LS = Application.International(wdListSeparator)
With H.Find
.Text = "^p "
.Replacement.Text = "^p"
.Execute Replace:=wdReplaceAll
.Text = " ^p"
.Replacement.Text = "^p"
.Execute Replace:=wdReplaceAll
.Text = "^p ^p"
.Replacement.Text = "^p^p"
.Execute Replace:=wdReplaceAll
.Text = "^13{2" & LS & "}"
.Replacement.Text = "^p"
.MatchWildcards = True
.Execute Replace:=wdReplaceAll
.Text = ""
.Style = wdStyleHeading2
.MatchWildcards = False
Do While .Execute
If H.Text <> vbCr Then
H.Collapse 0
H.Select
H.InsertParagraph
H.Delete
End If
H.Collapse 0
Loop
End With
Set H = ActiveDocument.Range
With H.Find
.Style = wdStyleHeading3
Do While .Execute
If H.Text <> vbCr Then
H.Collapse 0
H.Select
H.InsertParagraph
H.Delete
End If
H.Collapse 0
Loop
End With
End Sub
But somehow, it do not completely removed/replace the faulty paragraph marks. The above macro finds those paragraphs, add new and then remove it. which eventually removed the dotted line.
Can anybody explain this phenomena? what is the right ways to remove/replace those paragraphs. please download and see test file with error on page 7
Update: Even I tried with the following code but it did nothing (on MacOS Video). I think it is not finding the hidden paragraphs:
Sub HidNempty()
Dim H As Range
Set H = ActiveDocument.Range
With H.Find
.Text = "^p "
.Replacement.Text = "^p"
.Execute Replace:=wdReplaceAll
.Text = " ^p"
.Replacement.Text = "^p"
.Execute Replace:=wdReplaceAll
.Text = "^p ^p"
.Replacement.Text = "^p^p"
.Execute Replace:=wdReplaceAll
.Text = "^p"
Do While .Execute
If H.Font.Hidden = True Then
H.Font.Hidden = False
If Len(Trim(H.Paragraphs(1).Range.Text)) = 1 Then
H.Delete
End If
End If
Loop
End With
End Sub
To unhide all document paragraphs, please try the next piece of code:
Sub UnHideParagraphs()
Dim para As Paragraph
For Each para In ActiveDocument.Paragraphs
If para.Range.Font.Hidden Then
para.Range.Font.Hidden = False
End If
Next para
End Sub
It should work even if only part of the paragraph range is hidden...
Find/Replace won't delete duplicate paragraph breaks before a table, between tables, or after a table. Try:
Sub Demo()
Application.ScreenUpdating = False
Dim LS As String, Tbl As Table, bHid As Boolean
LS = Application.International(wdListSeparator)
bHid = ActiveWindow.View.ShowHiddenText
ActiveWindow.View.ShowHiddenText = True
With ActiveDocument.Range
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Format = True
.Forward = True
.Replacement.Font.Hidden = False
.Wrap = wdFindContinue
.MatchWildcards = False
.Text = "^p^w"
.Replacement.Text = "^p"
.Execute Replace:=wdReplaceAll
.Text = "^w^p"
.Execute Replace:=wdReplaceAll
.MatchWildcards = True
.Text = "^13{2" & LS & "}"
.Execute Replace:=wdReplaceAll
.Wrap = wdFindStop
End With
Do While .Find.Execute = True
With .Duplicate
.Font.Hidden = False
.Start = .Start + 1
.Text = vbNullString
End With
.Collapse wdCollapseEnd
.Find.Execute
Loop
End With
For Each Tbl In ActiveDocument.Range.Tables
With Tbl.Range
Do While .Characters.First.Previous.Previous = vbCr
.Characters.First.Previous.Previous = vbNullString
Loop
.Characters.First.Previous.Font.Hidden = False
Do While .Characters.Last.Next = vbCr
If .Characters.Last.Next.End = ActiveDocument.Range.End Then Exit Do
If .Characters.Last.Next.Next.Information(wdWithInTable) = True Then Exit Do
.Characters.Last.Next = vbNullString
Loop
.Characters.Last.Next.Font.Hidden = False
End With
Next
ActiveWindow.View.ShowHiddenText = bHid
Application.ScreenUpdating = True
End Sub
You will observe various lines in the code that apply .Font.Hidden = False. Depending on what you're trying to achieve visually, you may or may not want those.

Word VBA copy text formatted text in a certain font to a file and other formatting in other file

From a comparison docx file I need to extract into two word files the text formatted as strikethrough in one docx file and the text formatted as double underline in another docx file to be able to perform the wordcount of newly inserted and deleted text separately.
To do this, I wrote this macro, that actually activates the correct files, but only copies and pastes the formatting resulting from the first search.
Sub WSC_extraction_for_wordcount()
'This macro extracts double underlined text to the file "target_ins"
'This macro extracts strikethrough text to the file "target_del"
Application.ScreenUpdating = False
Selection.HomeKey Unit:=wdStory
Selection.Find.ClearFormatting
'STRIKETHROUGH processing
Do
With Selection.Find.Font
.StrikeThrough = True 'Then
Selection.Find.Execute FindText:="", Forward:=True, Format:=True
Selection.Cut
Windows("target_del.docx").Activate
Selection.PasteAndFormat (wdPasteDefault)
Selection.TypeParagraph
Windows("source.docx").Activate
End With
'DOUBLE UNDERLINE processing
With Selection.Find.Font
.Underline = wdUnderlineDouble = True 'Then
Selection.Find.Execute FindText:="", Forward:=True, Wrap:=wdFindContinue, Format:=True
Selection.Cut
Windows("target_ins.docx").Activate
Selection.PasteAndFormat (wdPasteDefault)
Selection.TypeParagraph
Windows("source.docx").Activate
End With
Loop
End Sub
I would be grateful if someone could help me in transforming the options into something like: if the next sentence you encounter is formatted as strikethrough, copy it to file target_del, if the next sentence you encounter is formatted as double underlined, copy it to the file target_ins.
Thank you in advance!
The code below avoids the use of the Selection object. It also assumes that the documents the text is to be moved to are already open.
Sub WSC_extraction_for_wordcount()
'This macro extracts double underlined text to the file "target_ins"
'This macro extracts strikethrough text to the file "target_del"
Application.ScreenUpdating = False
Dim source As Document: Set source = ActiveDocument
Dim targetDel As Document: Set targetDel = Documents("target_del.docx")
Dim targetIns As Document: Set targetIns = Documents("target_ins.docx")
'STRIKETHROUGH processing
With source.Content
With .Find
.ClearFormatting
.Text = ""
.Replacement.ClearFormatting
.Text = ""
.Forward = True
.Format = True
.Wrap = wdFindStop
.Font.StrikeThrough = True
End With
Do While .Find.Execute
targetDel.Characters.Last.FormattedText = .FormattedText
targetDel.Characters.Last.InsertParagraphAfter
.Delete
Loop
End With
'DOUBLE UNDERLINE processing
With source.Content
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Format = True
.Font.Underline = wdUnderlineDouble
End With
Do While .Find.Execute
targetIns.Characters.Last.FormattedText = .FormattedText
targetIns.Characters.Last.InsertParagraphAfter
.Delete
Loop
End With
End Sub
Without the overhead of creating new documents:
Sub Demo()
Application.ScreenUpdating = False
Dim i As Long, j As Long
With ActiveDocument.Range
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Font.Underline = wdUnderlineDouble
.Text = ""
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindStop
End With
Do While .Find.Execute
i = i + .ComputeStatistics(wdStatisticWords)
If .Information(wdWithInTable) = True Then
If .End = .Cells(1).Range.End - 1 Then
.End = .Cells(1).Range.End
.Collapse wdCollapseEnd
If .Information(wdAtEndOfRowMarker) = True Then
.End = .End + 1
End If
End If
End If
If .End = ActiveDocument.Range.End Then Exit Do
.Collapse wdCollapseEnd
Loop
End With
With ActiveDocument.Range
With .Find
.ClearFormatting
.Font.StrikeThrough = True
.Forward = True
.Wrap = wdFindStop
End With
Do While .Find.Execute
j = j + .ComputeStatistics(wdStatisticWords)
If .Information(wdWithInTable) = True Then
If .End = .Cells(1).Range.End - 1 Then
.End = .Cells(1).Range.End
.Collapse wdCollapseEnd
If .Information(wdAtEndOfRowMarker) = True Then
.End = .End + 1
End If
End If
End If
If .End = ActiveDocument.Range.End Then Exit Do
.Collapse wdCollapseEnd
Loop
End With
Application.ScreenUpdating = True
MsgBox i & " words added." & vbCr & j & " words deleted."
End Sub

How to find table column, then move down and replace the cell's content IF it is "N/A"

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

vba Word create a variable with value of text between 2 cursor points

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

Word VBA - Inserting Inline Picture from filepath in document

I have a Word Document that includes as text the complete filepaths to multiple images (e.g. C:\Users\Name\Documents\Test Logos\alphatest.png). I am trying to create a macro to replace each text filepath with the image it refers to as inline shapes. The script also resizes the images. I am having trouble assigning a valid reference to the inline shape object variable using the Set statement.
((Right now, I am locating the filepaths in the Word document by manually putting "QQQ" before and after the text in the Word Document and then having the script search for text that is flanked by "QQQ." So, in the Word Document, each filepath looks like this: "QQQC:\Users\Name\Documents\Test Logos\alphatest.pngQQQ". This is a temporary kludge and does not seem to be the source of the error.))
Sub InsertAndResizeLogos()
'
' InsertAndResizeLogos Macro
' Insert logos at the correct place in the document, resize to less than 1 inch tall and 2 inches wide.
'
Selection.HomeKey Unit:=wdStory
With Selection.Find
.ClearFormatting
.Text = "QQQ*QQQ"
.Forward = True
.Wrap = wdFindStop
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchAllWordForms = False
.MatchSoundsLike = False
.MatchWildcards = True
Do While .Execute
While Selection.Find.Found
Dim imagePath As String
Debug.Print Replace(Selection.Text, "QQQ", "")
imagePath = Replace(Selection.Text, "QQQ", "")
imagePath = Replace(imagePath, "\", "//")
imagePath = Replace(imagePath, vbCr, "")
Debug.Print imagePath
Dim SHP As InlineShape
Set SHP = Selection.InlineShapes.AddPicture(FileName:=imagePath, LinkToFile:=False, SaveWithDocument:=True)
SHP.LockAspectRatio = True
SHP.Height = InchesToPoints(1)
If SHP.Width > InchesToPoints(2) Then
SHP.Width = InchesToPoints(2)
End If
Wend
Loop
End With
End Sub
If I don't convert the filepath string to VBA's preferred format (i.e., removing this line from the script:)
imagePath = Replace(imagePath, "\", "//")
then the script successfully combs through the Word Document, finds the first filepath, and replaces it with the correct image. But then it throws a "Runtime Error 5152: This is not a valid file name." on the "Set" line and breaks.
If I do convert the filepath string to VBA format by replacing the \'s with //'s, then it does not successfully insert the image and throws a "Runtime Error 91: Object variable or With block variable not set" on the SHP.LockAspectRation=True line and breaks.
It seems like if I feed the filepath into the Set statement with //'s, it can no longer find the image. Is this something I could fix with error handling, or am I making a more fundamental mistake?
((If I set the filepath within the script, (i.e. imagePath = C:\Users\Name\Documents\Test Logos\alphatest.png), the script will successfully iterate through the entire document and replace all text with the QQQ's with that image.))
SOLUTION
Here is the final code that worked correctly:
Sub InsertAndResizeLogos()
'
' InsertAndResizeLogos Macro
' Insert logos at the correct place in the document, resize to less than 1 inch tall and 2 inches wide.
'
Application.ScreenUpdating = False
Dim i As Long, j As Long, StrNm As String, StrErr As String, iShp As InlineShape
With Selection 'ActiveDocument.Range
With .Find
.ClearFormatting
.Text = "*.[A-Za-z]{3}>"
.Forward = True
.Wrap = wdFindContinue
.Format = False
.MatchWildcards = True
.Execute
End With
Do While .Find.Found
StrNm = .Text
If Dir(StrNm) = "" Then
j = j + 1: StrErr = StrErr & vbCr & StrNm
Else
i = i + 1
Set iShp = .InlineShapes.AddPicture(FileName:=StrNm, LinkToFile:=False, SaveWithDocument:=True)
With iShp
.LockAspectRatio = True
.Height = InchesToPoints(1)
If .Width > InchesToPoints(2) Then .Width = InchesToPoints(2)
End With
End If
.Collapse wdCollapseEnd
.Find.Execute
Loop
End With
Application.ScreenUpdating = True
MsgBox i & " images added." & vbCr & j & " image files not found:" & StrErr
End Sub
The problem seems to have been related to pulling the filepath from Selection.Text rather than from .Find.Found.Text
This mostly uses the approach suggested below by Macropod, although applied to Selection rather than to Document.Range to maintain the "replace the text with the image" functionality. For some reason, Find.Execute's ReplaceWith parameter and Find's Replacement property refused to work no matter where in the process I called them.
You don't need all the QQQ circumlocution. You also don't need:
imagePath = Replace(imagePath, "\", "//")
But you should add error-checking to the code in case one or more image files is missing. Try:
Sub Demo()
Application.ScreenUpdating = False
Dim i As Long, j As Long, StrNm As String, StrErr As String, iShp As InlineShape
With ActiveDocument.Range
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = "C:\\Users\\*.[A-Za-z]{3}>"
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindStop
.Format = False
.MatchWildcards = True
.Execute
End With
Do While .Find.Found
StrNm = .Text
If Dir(StrNm) = "" Then
j = j + 1: StrErr = StrErr & vbCr & StrNm
Else
i = i + 1: .Text = vbNullString
Set iShp = .InlineShapes.AddPicture(FileName:=StrNm, LinkToFile:=False, SaveWithDocument:=True, Range:=.Duplicate)
With iShp
.LockAspectRatio = True
.Height = InchesToPoints(1)
If .Width > InchesToPoints(2) Then .Width = InchesToPoints(2)
End With
End If
.Collapse wdCollapseEnd
.Find.Execute
Loop
End With
Application.ScreenUpdating = True
MsgBox i & " images added." & vbCr & j & " image files not found:" & StrErr
End Sub
The following works for me.
I am using *png to identify the strings that end with .png.
I am then using
Right$(imagePath, Len(imagePath) - InStr(1,imagePath,":\") + 2)
to extract the string that holds the filepath on the assumption your filepaths are along the lines of C:\ etc. You could evolve this logic to suit your purposes.
I have removed the other loop and simply allowed the .Execute to continue until False.
Sub Test
Selection.HomeKey Unit:=wdStory
With Selection.Find
.ClearFormatting
.Text = "*png"
.Forward = True
.Wrap = wdFindContinue
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchAllWordForms = False
.MatchSoundsLike = False
.MatchWildcards = True
Do While .Execute
Dim imagePath As String
imagePath = Selection.Range.Text
imagePath = Right$(imagePath, Len(imagePath) - InStr(1,imagePath,":\") + 2)
Dim SHP As InlineShape
Set SHP = Selection.InlineShapes.AddPicture(FileName:=imagePath, LinkToFile:=False, SaveWithDocument:=True)
SHP.LockAspectRatio = True
SHP.Height = InchesToPoints(1)
If SHP.Width > InchesToPoints(2) Then
SHP.Width = InchesToPoints(2)
End If
Loop
End With
End Sub
Reference:
https://superuser.com/questions/1009085/find-all-instances-of-a-text-and-make-it-a-hyperlink-with-a-macro