VBA to find heading, delete, and move onto next heading - vba

I have the following code to find headings (ranging from heading 1-4) with the word "DELETE" in the heading to delete the heading and the text underneath, as well as nested headings. However, it stops after deleting the first set of headings it finds. How can I get it to work through all the headings in the document? Thank you!
Sub deleteheading()
Dim rngHeading1 As Range
Set rngHeading1 = GetHeadingBlock("DELETE", wdStyleHeading1)
If Not rngHeading1 Is Nothing Then rngHeading1.Delete
Dim rngHeading2 As Range
Set rngHeading2 = GetHeadingBlock("DELETE", wdStyleHeading2)
If Not rngHeading2 Is Nothing Then rngHeading2.Delete
Dim rngHeading3 As Range
Set rngHeading3 = GetHeadingBlock("DELETE", wdStyleHeading3)
If Not rngHeading3 Is Nothing Then rngHeading3.Delete
Dim rngHeading4 As Range
Set rngHeading4 = GetHeadingBlock("DELETE", wdStyleHeading4)
If Not rngHeading4 Is Nothing Then rngHeading4.Delete
End Sub
Function GetHeadingBlock(headingText As String, headingStyle As WdBuiltinStyle) As Range
Dim rngFind As Range
Set rngFind = ActiveDocument.Content
With rngFind.Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = "DELETE"
.style = headingStyle
.Replacement.Text = ""
.Forward = True
.Format = True
.Wrap = wdFindStop
If .Execute Then Set GetHeadingBlock = _
rngFind.GoTo(What:=wdGoToBookmark, Name:="\HeadingLevel")
End With
End Function

For example:
Sub DeleteHeadingSpanText()
Application.ScreenUpdating = False
Dim h As Long
With ActiveDocument.Range
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = "DELETE"
.Replacement.Text = ""
.Format = True
.Forward = True
.MatchCase = True
.MatchWholeWord = True
.Wrap = wdFindContinue
End With
For h = 1 To 9
.Style = "Heading " & h
Do While .Find.Execute
.Duplicate.GoTo(What:=wdGoToBookmark, Name:="\HeadingLevel").Text = vbNullString
Loop
Next
End With
Set RngHd = Nothing
Application.ScreenUpdating = True
End Sub
Change the 1 & 9 in 'For h = 1 To 9' to define whatever heading levels you want to limit the code's scope to.

This code calls your own function GetHeadingBlock.
Sub DeleteHeading()
Dim rngHeading As Range
Dim i As WdBuiltinStyle
For i = wdStyleHeading1 To wdStyleHeading4 Step -1
Do
Set rngHeading = GetHeadingBlock("DELETE", i)
If rngHeading Is Nothing Then
Exit Do
Else
rngHeading.Delete
End If
Loop
Next i
End Sub

Related

Range.Find Word VBA: finding heading with specific heading number only works if heading style is specified

I'd like to find the location of a heading that has a specific heading number. E.g. "2.3."
For some reason, I can only find the location of the heading if i specify what Style that heading is going to be. If i don't specify the heading style then I don't get any matches (i.e. .Execute is never True).
How can I find the location of a heading without having to specify it's style?
Code that works:
Function FindHeadingPos(oRng As Word.Range) As Long
Dim rng As Word.Range
With oRng.Find
.ClearAllFuzzyOptions
.ClearHitHighlight
.ClearFormatting
.Text = ""
.Forward = True
.Wrap = 2
.Format = True
.Style = "Heading 2,H2 Numb"
Do While .Execute
'.Parent contains the found range
Set rng = .Parent
If rng.ListFormat.ListString = "2.3." Then
FindHeadingPos = rng.Start
Exit Do
End If
'below statement seems to prevent code hanging on some headings.
rng.Collapse Direction:=wdCollapseEnd
Loop
End With
End Function
Code that doesn't work:
Function FindHeadingPos(oRng As Word.Range) As Long
Dim rng As Word.Range
With oRng.Find
.ClearAllFuzzyOptions
.ClearHitHighlight
.ClearFormatting
.Text = ""
.Forward = True
.Wrap = 2
'.Format = True
'.Style = "Heading 2,H2 Numb"
Do While .Execute
'.Parent contains the found range
Set rng = .Parent
If rng.ListFormat.ListString = "2.3." Then
FindHeadingPos = rng.Start
Exit Do
End If
'below statement seems to prevent code hanging on some headings.
rng.Collapse Direction:=wdCollapseEnd
Loop
End With
End Function
Thanks #GSerg for suggesting the .ParagraphFormat.OutlineLevel property.
The code below seems to solve my problem in case it helps anyone else.
Function getParaOutlineLevel(headNumberRaw As String) As Integer
Dim numberOfDecimals As Integer
numberOfDecimals = Len(headNumberRaw) - Len(Replace(headNumberRaw, ".", ""))
If Not IsNumeric(Left(headNumberRaw, 1)) Then
getParaOutlineLevel = numberOfDecimals + 5
Else
getParaOutlineLevel = numberOfDecimals
End If
End Function
Function FindHeadingPos(oRng As Word.Range) As Long
Dim headNumber As String
Dim rng As Word.Range
headNumber = "2.3."
With oRng.Find
.ClearAllFuzzyOptions
.ClearHitHighlight
.ClearFormatting
.Text = ""
.Forward = True
.Wrap = 2
.Format = True
.ParagraphFormat.OutlineLevel = getParaOutlineLevel(headNumber)
Do While .Execute
'.Parent contains the found range
Set rng = .Parent
If rng.ListFormat.ListString = headNumber Then
FindHeadingPos = rng.Start
Exit Do
End If
'below statement seems to prevent it hanging on some headings.
rng.Collapse Direction:=wdCollapseEnd
Loop
End With
End Function

How to dynamically select a range and delete it

this is my first post here!
I am new to Microsoft VBA, but I need to write some macros to quickly make the same changes to 200+ documents. I took the Udemy course on Word VBA but I am stuck trying to figure out how to address the following issues:
I need to select all content from beginning of doc up until the first occurrence of the string "following:" including the string itself - the issue is that for each doc, this string will always be in a different position and the portion I want to delete will vary in length. The only guarantee is that it will always be on the first page.
I need to do the same thing for the end of the document - I need to delete all content following the string "Affirmative Defenses" including the string itself - again, this will always be in a different position and will not always be on the last page (unlike issue number 1)
I have written many variations by reading other questions/solutions with no luck. Below is my current version but it does not work.
Sub DeleteBegin()
Dim findRng As Range
Set findRng = ActiveDocument.Range
Dim endPara As Long
With findRng.Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = "following."
.Replacement.Text = ""
.Wrap = wdFindStop
.MatchWholeWord = True
.Forward = True
.Execute
If .Found = True Then
endPara = GetParaNum(findRng)
findRng.Start = 0
findRng.End = endPara
End If
Dim capRng As Range
Set capRng = ActiveDocument.Range
capRng.SetRange Start:=0, End:=endPara
capRng.Select
Selection.Delete
End With
End Sub
Function GetParaNum(ByRef r As Object) As Integer
Dim rPara As Object
Dim CurPos As Long
r.Select
CurPos = ActiveDocument.Bookmarks("\startOfSel").Start
Set rPara = ActiveDocument.Range(Start:=0, End:=CurPos)
GetParaNum = rPara.Paragraphs.Count
End Function
Try:
Sub Demo()
Application.ScreenUpdating = False
Dim Rng As Range
With ActiveDocument
Set Rng = .Range(0, 0)
With .Range
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = "following."
.Replacement.Text = ""
.Format = False
.Forward = True
.Wrap = wdFindStop
.Execute
End With
If .Find.Found = True Then
Rng.End = .Duplicate.End
Rng.Delete
End If
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = "Affirmative Defenses"
.Replacement.Text = ""
.Format = False
.Forward = True
.Wrap = wdFindStop
.MatchCase = True
.Execute
End With
If .Find.Found = True Then
Set Rng = .Duplicate
Rng.End = ActiveDocument.Range.End
Rng.Delete
End If
End With
End With
Application.ScreenUpdating = True
End Sub

How can I convert a word to a hyperlink linking to a Bookmark in the same document?

I really have problems with this one. Imagine I have the word „stackoverflow“. At the end of the document there is a glossary. Now I need a macro that searches for all occurences of stackoverflow and replaces them with a hyperlink to the bookmark in the table. A reader still sees „stackoverflow“ but can click on it to jump to the Glossary. I can insert online links in „address“ field and think I need the subaddress field but do not know what to put there.. Thank you in advance!
Sub Convert_String()
Dim Word
Dim R As Range
Dim Tabellenanzahl
Dim T As Table
Dim Link As Hyperlink
Set R = ActiveDocument.Range
Tabellenanzahl = ActiveDocument.Tables.Count
Set T = ActiveDocument.Tables(Tabellenanzahl)
ActiveDocument.Bookmarks.Add "Anker", T.Range
For Z = 2 To T.Rows.Count
Set Wort = T.Cell(Z, 1)
With R.Find
.ClearFormatting
.Text = Word
.Forward = True
.Wrap = wdFindStop
End With
Do While R.Find.Execute
R.Hyperlinks.Add Anchor:=Selection, SubAddress:="Anker", TextToDisplay:="GoToGlossaryTest"
Loop
Next
End Sub
Try:
Sub GlossaryLinker()
Application.ScreenUpdating = False
Dim Tbl As Table, Rng As Range, HLnk As Hyperlink
Dim strFnd As String, BkMkNm As String, r As Long
With ActiveDocument
Set Tbl = .Tables(.Tables.Count)
For r = 2 To Tbl.Rows.Count
With Tbl.Cell(r, 1)
Set Rng = .Range
With Rng
.End = .End - 1
strFnd = Trim(Split(.Text, vbCr)(0))
BkMkNm = Replace(strFnd, " ", "_")
.Bookmarks.Add BkMkNm, .Duplicate
End With
End With
Set Rng = .Range(.Range.Start, Tbl.Range.Start)
With .Range
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Format = False
.Text = strFnd
.Wrap = wdFindStop
.MatchWholeWord = True
.MatchWildcards = False
.MatchCase = True
.Execute
End With
Do While .Find.Found
If .InRange(Rng) = False Then Exit Do
Set HLnk = .Hyperlinks.Add(.Duplicate, , BkMkNm, , .Text)
.End = HLnk.Range.End
.Collapse wdCollapseEnd
.Find.Execute
Loop
End With
Next
End With
Application.ScreenUpdating = True
End Sub

Replacing same occurrences of a string by different values in ms-word

I have a text with five 'XX' scattered at different places. I'd like to
replace the first instance of XX by 1., the second instance by 2. and
so, until replacing the fifth instance by 5. I tried to use the
following code without success:
Selection.Find.ClearFormatting
Selection.Find.Replacement.ClearFormatting
With Selection.Find
.Text = "XX"
.Replacement.Text = "1."
.Execute Replace:=wdReplaceOne
.Forward = True
.Text = "XX"
.Replacement.Text = "2."
.Execute Replace:=wdReplaceOne
.Forward = True
[...]
.Text = "XX"
.Replacement.Text = "5."
.Execute Replace:=wdReplaceOne
.Wrap = wdFindStop
End With
End Sub
How can I modify the above code, or what else should I do to get these substitutions? If I use "sed" on a text file, I'd simply do: s/XX/1./1, s/XX/2./2, s/XX/3./3, etc.
What you can do is use a For...Next loop to increment a counter, using the counter as the replacement text. This will save having to write lots of repeated code, as the first code sample shows.
The code can be made more flexible, for any number of occurrences of the search term, by using a Do...Until loop that repeats until no more instances of the search term are found. This variation is in the second code example.
Both variations contain code to search either the entire document or the current selection. Just comment out the one you don't need and remove the comment from the one you do...
Sub FindAndReplaceWithNumbers()
Dim rngDoc As word.Range, rngFind As word.Range
Dim findString As String
Dim counter As Long
Dim found As Boolean
findString = "XX"
'To search the entire document
'Set rngDoc = ActiveDocument.content
'To search a selection, only
Set rngDoc = Selection.Range
Set rngFind = rngDoc.Duplicate
With rngFind.Find
.ClearFormatting
.Replacement.ClearFormatting
.wrap = wdFindStop
.Forward = True
.Text = findString
End With
For counter = 1 To 5
With rngFind.Find
.Replacement.Text = CStr(counter) & "."
found = .Execute(Replace:=wdReplaceOne)
End With
rngFind.End = rngDoc.End
Next
End Sub
Sub FindAndReplaceWithNumbers()
Dim rngDoc As word.Range, rngFind As word.Range
Dim findString As String
Dim counter As Long
Dim found As Boolean
findString = "XX"
counter = 1
'To search the entire document
'Set rngDoc = ActiveDocument.content
'To search a selection, only
Set rngDoc = Selection.Range
Set rngFind = rngDoc.Duplicate
With rngFind.Find
.ClearFormatting
.Replacement.ClearFormatting
.wrap = wdFindStop
.Forward = True
.Text = findString
End With
Do
With rngFind.Find
.Replacement.Text = CStr(counter) & "."
found = .Execute(Replace:=wdReplaceOne)
End With
rngFind.End = rngDoc.End
counter = counter + 1
Loop Until Not found
End Sub
Simpler and faster:
Sub Demo()
Application.ScreenUpdating = False
Dim i As Long
With ActiveDocument.Range
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = "XX"
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindStop
.MatchWildcards = True
.Execute
End With
Do While .Find.Found
i = i + 1
.Text = i
.Collapse wdCollapseEnd
.Find.Execute
Loop
End With
Application.ScreenUpdating = True
MsgBox i & " records updated."
End Sub
To limit the code's scope to a Selection, you could use:
Sub Demo()
Application.ScreenUpdating = False
Dim Rng As Range, i As Long
With Selection
Set Rng = .Range
With .Range
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = "XX"
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindStop
.MatchWildcards = True
.Execute
End With
Do While .Find.Found
If .InRange(Rng) Then
i = i + 1
.Text = i
Else
Exit Do
End If
.Collapse wdCollapseEnd
.Find.Execute
Loop
End With
End With
Application.ScreenUpdating = True
MsgBox i & " records updated."
End Sub

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