Create Word table with text - vba

I would like to reformat an existing and recurring document.
The document is available in two almost identical versions.
The script should search the whole document for the word "ColumnA" and set a starting point for the table behind it.
Then it should search for the word "ContinuousText" or a "Page Break" and create an end point for the table before that.
This is also the difference between the two documents. One has more text (ContinuousText) and the other has no more text but only a "Page Break".
My script works fine when I have "ColumnA" and "ContinuousText".
How do I insert a if there is no "ContinuousText" - looking for "Page Break" query?
This is the scipt that works ("ColumnA" and "ContinuousText")
Sub SlideNoteToTable()
' -----------------< Create Table >-----------------
Dim suchBereich As Range, TabBereich As Range, tabelle As Table
Dim collStart As Collection, collEnd As Collection
Dim d As Long
Set collStart = New Collection: Set collEnd = New Collection
'Collect starting points for the table areas (ColumnA- Ende)
Set suchBereich = ActiveDocument.Range
With suchBereich.Find
.Text = "ColumnA"
Do While .Execute
collStart.Add suchBereich.Paragraphs(1).Range.End + 1
Loop
End With
' Endpunkte für die Tabellenbereiche sammeln (ContinuousText- Text Start)
Set suchBereich = ActiveDocument.Range
With suchBereich.Find
.Text = "ContinuousText"
Do While .Execute
collEnd.Add suchBereich.Start - 1
Loop
End With
'Convert areas to table
For d = collStart.Count To 1 Step -1
Set TabBereich = ActiveDocument.Range(collStart(d), collEnd(d))
Set tabelle = TabBereich.ConvertToTable(Separator:=wdSeparateByParagraphs, NumColumns:=2, AutoFitBehavior:=wdAutoFitWindow)
With tabelle
'all table formatting operations
.AllowAutoFit = False
.PreferredWidthType = wdPreferredWidthPoints
.Borders.Enable = True
.Rows(1).HeadingFormat = True
.Columns(1).SetWidth ColumnWidth:=.PreferredWidth * 2 / 3, RulerStyle:=wdAdjustProportional
End With
Next d
' -----------------< Delete empty tables >-----------------
Dim tabelleX As Table, zeile As Row
For Each tabelleX In ActiveDocument.Tables
For Each zeile In tabelleX.Rows
If Len(zeile.Range) = 4 Then 'there's nothing in it but an empty paragraph mark
zeile.Delete
End If
Next zeile
Next tabelleX
End Sub
I tried to solve the problem pragmatically by simply changing:
.Text = "ContinuousText"
to
.Text = "ContinuousText" Or "^m"
Okay, you can stop laughing now.
I've noticed that it's not quite that easy. But how do I get such an "or" query?
Many thanks for your help.

You cannot use anything like:
.Text = "ContinuousText" Or "^m"
or
.Text = "ContinuousText" Or .Text = "^m"
As a VBA Find expression.
As described in my answer to your other thread on the related issue, you could use two wildcard Find loops, the first being for:
.Text = "ColumnA[!^m]#ContinuousText"
to locate all strings from 'ColumnA' to 'ContinuousText' without an intervening manual page break.
You could then use a separate loop for:
.Text = "ColumnA*^m"
to locate all strings from 'ColumnA' to the next manual page break and couple that with a test on the found range like:
If Instr(.Text, "ContinuousText") = 0 Then
'do the table construction
End If
By putting the code for the table construction in a separate Sub that your main routine calls, you can minimize the code duplication.

I understand your first snippet of code...
.Text = "ContinuousText" Or "^m"
and I have integrated it into the script.
Sub SlideNoteToTable2()
'
' SlideNoteToTable2 Macro
' Formats the speaker text into a two-column table
'
Application.ScreenUpdating = False
' -----------------< Reduce all images proportionally by 40% >-----------------
Dim i As Long
With ActiveDocument.Range
For i = 1 To .InlineShapes.Count
With .InlineShapes(i)
.ScaleHeight = 50
.ScaleWidth = 50
End With
Next i
' ----------------- Locate everything from 'Slide notes' to 'Text Captions' by a Wildcard >-----------------
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = "Slide notes[!^m]#Text Captions"
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindStop
.Format = False
.MatchWildcards = True
End With
' ----------------- Replacing the two phrases 'Slide notes & Text Captions' with 'Speaker text: & Screen text:' >-----------------
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
' ----------------- Converting the intervening content to a two-column table >-----------------
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 * 3 / 4, 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
I don't know what to do with the other two snippets of code and where to put them.
.Text = "ColumnA*^m"
'
If Instr(.Text, "ContinuousText") = 0 Then
'do the table construction
End If
I tried a few things that unfortunately didn't work.
Many thanks for the help,
Kind regards.

Related

Word Macro to select paragraph with specific words and copy to new document

I am trying to create a Word macro that will:
Search for a specific word (i.e. "see")
Select the entire paragraph where that word appears
Make the whole paragraph a different style (i.e. make it all red text)
Do the same thing with a second word (i.e. "blacklist")
Select that whole paragraph and apply a different style (i.e. again, make the paragraph red text)
Copy all paragraphs with the red text style and paste them in to a new word document
Unfortunately, I'm no VBA expert and I'm trying to cobble things together from what I can find online. I have found a great example that will select to the start of the paragraph, but I can't seem to figure out how to select the entire paragraph. Any help is appreciated!
** Sorry - here is the code I currently have. It will find all instances of the word "see" and selects to the start of the paragraph, then changes the color to red... but that's as far as I've gotten, as I am stuck on trying to figure out how to get it to select to the end of the paragraph.
Sub TestOne()
'
' TestOne Macro
'
'
If MsgBox(Prompt:="Would you like to update selected paragraph styles?", Buttons:=vbYesNo + vbQuestion, _
Title:="Format MD Report") = vbNo Then
Exit Sub
End If
Application.ScreenUpdating = False
Dim i As Long
With ActiveDocument.Range
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = "see"
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindStop
.Format = False
.MatchWildcards = False
End With
Do While .Find.Execute
i = i + 1
.Start = .Paragraphs.First.Range.Start
.Font.Color = wdColorRed
.Start = .Paragraphs.First.Range.End
Loop
End With
Application.ScreenUpdating = True
MsgBox i & " instances processed."
End Sub
For example, without needing to create a second document:
Sub Demo()
Application.ScreenUpdating = False
Dim i As Long, StrFnd As String
StrFnd = "see|blacklist"
With ActiveDocument.Range
.Font.Hidden = True
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Replacement.Text = "^&"
.Font.Hidden = True
.Replacement.Font.Hidden = False
.Format = True
.Forward = True
.MatchWildcards = True
.Wrap = wdFindContinue
For i = 0 To UBound(Split(StrFnd, "|"))
.Text = "[!^13]#" & Split(StrFnd, "|")(i) & "*^13"
.Execute Replace:=wdReplaceAll
Next
.Replacement.ClearFormatting
.Text = ""
.Replacement.Text = ""
.Execute Replace:=wdReplaceAll
End With
End With
Application.ScreenUpdating = True
End Sub
You could, of course, add a line of code before the final 'End With' to save the document with a new name.
To select the entire paragraph, following the line
.Start = .Paragraphs.First.Range.Start
add
.End = .Paragraphs.First.Range.End
... then to match only whole words, after
.MatchWildcards = False
add
.MatchWholeWord = True
And to run the code for multiple words you should add a parameter to your Sub eg
Sub TestOne(theWord As String)
then replace
.Text = "see"
with
.Text = theWord
And to run your code for each required word, add a Sub such as
Sub RunMe()
TestOne "see"
TestOne "blacklist"
End Sub
... optionally, move your MsgBoxes into RunMe()

VBA Loop in Word to find wildcard strings misses first occurrence

I have some VBA for Microsoft Word that is supposed to find some five digit numbers using wildcards in multiple files and then the sticks them and the path/file into an excel file. Unfortunately, it ALWAYS misses the first occurrence of the wildcard string. I cannot determine why!
I've tried reordering things to make sure that it's not being missed, however, I am unable to get it working properly. When I run the wildcard search myself by hand, it finds the first occurence. It doesn't do it in VBA, however.
Public Sub TestFindNumbers()
Dim i As Long
i = 2 ' Row in Excel to start
Dim ObjExcel As Object, ObjWorkBook As Object, ObjWorksheet As Object
Set ObjExcel = CreateObject("EXCEL.APPLICATION")
Set ObjWorkBook = ObjExcel.Workbooks.Add
Set ObjWorksheet = ObjWorkBook.Worksheets("Sheet1")
Set dlgFile = Application.FileDialog(msoFileDialogFilePicker)
With dlgFile
dlgFile.AllowMultiSelect = True
If .Show = -1 Then
For nDocx = 1 To dlgFile.SelectedItems.Count
Documents.Open dlgFile.SelectedItems(nDocx)
Set objDocx = ActiveDocument
With objDocx.Range
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = "[0-9]{5}"
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindStop
.Format = False
.MatchWildcards = True
.Execute
End With
Do While .Find.Found
.Collapse wdCollapseEnd
.Find.Execute
If .Text <> "" Then
ObjWorksheet.Cells(i, 1) = Left(.Text, 8)
ObjWorksheet.Cells(i, 2) = dlgFile.SelectedItems(nDocx)
Else
i = i - 1
End If
i = i + 1
Loop
End With
objDocx.Close SaveChanges:=wdDoNotSaveChanges
Next nDocx
Else
MsgBox ("You need to select documents first!")
Exit Sub
End If
End With
ObjWorksheet.Cells(1, 1) = "Number"
ObjWorksheet.Cells(1, 2) = "Path & Filename"
ObjExcel.Visible = 1
Set objDocx = Nothing
Set ObjExcel = Nothing
Set ObjWorkBook = Nothing
Set ObjWorksheet = Nothing
End Sub
I created a single test file with the following:
1234 Shouldn’t be selected
12345 Select this one. First occurrence.
98765 Another good one
568 Nope
This one is 55555 in the middle
End
When I run my VBA code, I'm getting 98765 and 55555 as hits. Unfortunately, 12345 isn't being found.
The reason the code in the question is not finding the search terms as expected:
The Collapse, then Find.Execute methods are in the loop before the first result is picked up. Since .Execute is also in the With block preceding the loop, Find runs twice, thus masking the first occurrence of the search term.
In addition:
1) Preferably, a specific Range should be used for the search, rather than the entire document (objDocx.Range). This is due to the "collapsing" - it works more reliably when there's a specific Range object.
2) Do not use Find.Wrap = wdFindContinue as suggested in comments. wdFindStop (as in the code in the question) is correct when using Find in a loop. wdFindContinue will often lead to an "infinite loop" as Word will start at the beginning of the document again, and again...
3) It's possible (better) to set a Document object when a file is being opened (or created), rather than relying on ActiveDocument in a second step:
Set objDocx = Documents.Open dlgFile.SelectedItems(nDocx)
Here's the part of the code that has to do with the Find - I've left out the Excel parts to make it easier to read
Dim objDocx As Word.Document
Dim rngFind As Word.Range
Set objDocx = Documents.Open dlgFile.SelectedItems(nDocx)
Set rngFind = objDocx.content
With rngFind
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = "[0-9]{5}"
.Replacement.Text = ""
.Forward = True
.wrap = wdFindStop
.Format = False
.MatchWildcards = True
.Execute
End With
Do While .Find.Found
If .Text <> "" Then
ObjWorksheet.Cells(i, 1) = Left(.Text, 8)
ObjWorksheet.Cells(i, 2) = dlgFile.SelectedItems(nDocx)
Else
i = i - 1
End If
i = i + 1
.Collapse wdCollapseEnd
.Find.Execute
Loop
End With
The problem is with your Do While loop. Change it to:
Do While .Find.Found
ObjWorksheet.Cells(i, 1) = Left(.Text, 8)
ObjWorksheet.Cells(i, 2) = objDocx.Name
i = i + 1
.Collapse wdCollapseEnd
.Find.Execute
Loop
Also, instead of:
Documents.Open dlgFile.SelectedItems(nDocx)
Set objDocx = ActiveDocument
use:
Set objDocx = Documents.Open(dlgFile.SelectedItems(nDocx))

VBA and MSWord: Use multiple values of a find parameter in Find/Execute routine

I have a Find/Execute routine that looks for paragraphs in my custom style, Bullet_Type_1_Level_1, which is a custom bulleted list style, and processes the paragraphs. (It checks each paragraph in the given range to see if it terminates in a period or not, but that's not important for this question). The routine currently works fine, but I want to expand it to search for additional levels--which translates into additional styles--of my outline list and to search for a style in another list, too. Is there a compact way to have my code also look for paragraphs in Bullet_Type_1_Level_2 and numlist_Level_1 (and process them, too) while it's at it? Here's the guts of my existing code:
For Each para In RangeToCheck.Paragraphs
With Selection.Find
.Text = ""
.Style = "Bullet_Type_1_Level_1"
.Wrap = wdFindStop
.Execute
Do While .Found = True 'Look for the specified style
strSentence = Selection.Text
'Test the string using a block of code that I'm omitting, for brevity.
'Finally, depending on what happened, put or don't a period at the end of the original range.
End With
Next para
You can add another loop.
Declare i (or more meaningful variable name), and loop through that.
Dim i As Long
For Each para In RangeToCheck.Paragraphs
For i = 1 To 3
With Selection.Find
.Text = ""
Select Case i
Case 1
.Style = "Bullet_Type_1_Level_1"
Case 2
.Style = "Bullet_Type_1_Level_2"
Case 3
.Style = "numlist_Level_1"
End Select
.Wrap = wdFindStop
.Execute
Do While .Found = True 'Look for the specified style
strSentence = Selection.Text
'Test the string using a block of code that I'm omitting, for brevity.
'Finally, depending on what happened, put or don't a period at the end of the original range.
End With
Next i
Next para
Probably not the prettiest solution out there - word is not my strong point ☺.
An alternative approach that may be quicker if there are paragraphs that are none of those Styles:
Dim i As Long
For i = 1 To 3
With RangeToCheck
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = ""
.Replacement.Text = ""
.Forward = True
.Format = True
.Wrap = wdFindStop
.Style = "Bullet_Type_1_Level_" & i
.Execute
End With
Do While .Find.Found = True
If .InRange(RangeToCheck) = False Then Exit Do
Select Case i
Case 1 'Do something for Bullet_Type_1_Level_1
Case 2 'Do something for Bullet_Type_1_Level_2
Case 3 'Do something for Bullet_Type_1_Level_3
End Select
If ActiveDocument.Range.End = RangeToCheck.Range.End Then Exit Do
.Collapse wdCollapseEnd
.Find.Execute
Loop
End With
Next

Word VBA copy highlighted text to new document and preserve formatting

I have a word document with multiple highlighted words that I want to copy into another word file. The code I'm using works fine, but does not preserve the original formatting in the source document. Here's the entire code (1st section finds words using wildcards and highlights them, and the 2nd section finds the highlighted words and copies them to a new word document):
Sub testcopytonewdoc2()
'
Dim ThisDoc As Document
Dim ThatDoc As Document
Dim r, newr, destr As Range
Dim rangestart, rangeend As Long
Set r = ActiveDocument.Range
rangeend = r.Characters.Count
r.Find.Execute FindText:="39.13 [Amended]"
rangestart = r.Start
'find words and highlight them
x = 0
Do While x < 4
Application.ScreenUpdating = False
Options.DefaultHighlightColorIndex = wdYellow
With ActiveDocument.Content.Find
'.ClearFormatting
If x = 0 Then
.text = "[!)][(][1-9][)]?{7}"
ElseIf x = 1 Then
.text = "[!?][(][a-z][)][ ][A-Z]?{6}"
ElseIf x = 2 Then
.text = "[!?][(][ivx]{2}[)][ ][A-Z]?{6}"
Else
.text = "[!?][(][ivx]{3}[)][ ][A-Z]?{6}"
End If
With .Replacement
' .ClearFormatting
.Highlight = True
End With
.Forward = True
.Wrap = wdFindContinue
.Format = True
.MatchWildcards = True
.Execute Replace:=wdReplaceAll
End With
Application.ScreenUpdating = True
x = x + 1
Loop
Set ThisDoc = ActiveDocument
Set newr = ThisDoc.Range
Set ThatDoc = Documents.Add
newr.SetRange Start:=rangestart, End:=rangeend
'find highlighted words and add to a new document (preserve BOLD font):
With newr.Find
.text = ""
.Highlight = True
.Format = True
.Wrap = wdFindStop
While .Execute
Set destr = ThatDoc.Range
destr.Collapse wdCollapseEnd
destr.FormattedText = newr.FormattedText
ThatDoc.Range.InsertParagraphAfter
newr.Collapse wdCollapseEnd
Wend
End With
Application.ScreenUpdating = True
End Sub
Can anyone help? The highlighted words are a mix of bold and non-bold text and it's important to maintain this difference. Thanks in advance for your help!
Holly
Try it this way.
Sub ExtractHighlightedText()
Dim oDoc As Document
Dim s As String
With Selection
.HomeKey Unit:=wdStory
With .Find
.ClearFormatting
.Text = ""
.Highlight = True
Do While .Execute
s = s & Selection.Text & vbCrLf
Loop
End With
End With
Set oDoc = Documents.Add
oDoc.Range.InsertAfter s
End Sub
This comes from my book.
http://www.lulu.com/shop/ryan-shuell/ebook/product-22936385.html

Remove all text between 2 headers Word 2010, using VBA

I have 2 headers or markers that are a part of my RTF document. In my example I am showing a sentence when in reality it will be multiple sentences or paragraphs. I have used brackets instead of less than and greater than signs as they disappear in my question. All I want to do is replace the text between the 2 markers with the following sentence, "text goes here", without quotation marks.
[EmbeddedReport]Lots of text, thousands of character, multiple paragraphs[/EmbeddedReport]
I want replace all the text between the 2 markers replaced with "text goes here".
It would end up looking like this...
"[EmbeddedReport]text goes here[/EmbeddedReport]"
I've literally spent 2 days trying to solve this. Any help would be appreciated.
This is the last thing I tried...
Sub RemoveReport()
Dim c As Range
Dim StartWord As String, EndWord As String
Selection.HomeKey Unit:=wdStory
StartWord = "<ImageTable>"
EndWord = "</ImageTable>"
Set c = ActiveDocument.Content
c.Find.ClearFormatting
c.Find.Replacement.ClearFormatting
With c.Find
.Text = StartWord & "*" & EndWord
' MsgBox (.Text)
.Replacement.Text = "<ImageTable>text goes here</ImageTable>"
.Forward = True
.Wrap = wdFindStop
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = True
.MatchSoundsLike = False
.MatchAllWordForms = False
End With
c.Find.Execute
While c.Find.Found
Debug.Print c.Text
'~~> I am assuming that the start word and the end word will only
'~~> be in the start and end respectively and not in the middle
Debug.Print Replace(Replace(c.Text, StartWord, ""), EndWord, "")
c.Find.Execute
Wend
End Sub
Word VBA is not my area of expertise, but it seems similar to a question I answered a few days ago.
Turns out the wildcard match was not doing what I hoped it would do, or at least it was not reliable. Also, I ran in to some trouble using angle brackets, so this uses square brackets. I suspect that word treats the angle brackets as markup/syntax, and thus does not interpret them as text in the Find object. There is probably a way around this, but Word VBA is not my specialty. There is also probably a more elegant solution, but again, Word VBA is not my specialty :)
Try something like this:
Option Explicit
Sub Test()
Dim doc As Document
Dim txtRange As Range
Dim startTag As String
Dim endTag As String
Dim s As Long
Dim e As Long
startTag = "[EmbeddedReport]"
endTag = "[/EmbeddedReport]"
Set doc = ActiveDocument
Set txtRange = doc.Content
'Find the opening tag
With txtRange.Find
.Text = startTag
.Forward = True
.Execute
If .Found Then
s = txtRange.Start
Else
GoTo EarlyExit
End If
End With
'Find the closing tag
Set txtRange = doc.Range(txtRange.End, doc.Content.End)
With txtRange.Find
.Text = endTag
.Forward = True
.Execute
If .Found Then
e = txtRange.End
Else
GoTo EarlyExit
End If
End With
Set txtRange = doc.Range(s, e)
txtRange.Text = startTag & "text goes here" & endTag
Exit Sub
EarlyExit:
MsgBox "Header not found in this document!", vbInformation
End Sub
It takes some time to figure it out at first, but learning to navigate the object model reference documentation for VBA will make these tasks a lot easier to figure out in the future.