I've written a VBA Word Macro that read a .txt File, copy it and paste it in a Word document setting a new font.
All is working fine! Now I would like to highlight some specific lines with bold + italic font, but i cannot figure out a working solution.
The specific lines begins with a specific word (for example Simulation Nr.xxx) or they begin with some words but then they have a very long series of blank spaces (for example Turbine).
How can i solve the problem?
P.s.: here the working code that copy/paste the .txt file into a word document.
Sub ACTUS_Table_Converter()
Dim pName As String
Dim bDoc As Document
Dim AppPath, ThisPath As String
Dim Rng As Range
ThisPath = ActiveDocument.Path
pName = ActiveDocument.Name
With Dialogs(wdDialogFileOpen)
If .Display Then
If .Name <> "" Then
Set bDoc = Documents.Open(.Name)
AppPath = bDoc.Path
End If
Else
MsgBox "No file selected"
End If
End With
Call ReplaceAllxSymbolsWithySymbols
Call ChangeFormat
Selection.Copy
Windows(pName).Activate
Selection.Paste
Selection.Collapse
bDoc.Close savechanges:=False
End Sub
Sub ChangeFormat()
Selection.WholeStory
With Selection.Font
.Name = "Courier New"
.Size = 6
End With
End Sub
Sub ReplaceAllxSymbolsWithySymbols()
'Call the main "ReplaceAllSymbols" macro (below),
'and tell it which character code and font to search for, and which to replace with
Call ReplaceAllSymbols(FindChar:=ChrW(-141), FindFont:="(normal text)", _
ReplaceChar:=ChrW(179), ReplaceFont:="(normal text)")
Call ReplaceAllSymbols(FindChar:=ChrW(-142), FindFont:="(normal text)", _
ReplaceChar:=ChrW(178), ReplaceFont:="(normal text)")
Call ReplaceAllSymbols(FindChar:=ChrW(-144), FindFont:="(normal text)", _
ReplaceChar:=ChrW(176), ReplaceFont:="(normal text)")
Call ReplaceAllSymbols(FindChar:="°", FindFont:="(normal text)", _
ReplaceChar:="", ReplaceFont:="(normal text)")
End Sub
Sub ReplaceAllSymbols(FindChar As String, FindFont As String, _
ReplaceChar As String, ReplaceFont As String)
Dim FoundFont As String, OriginalRange As Range, strFound As Boolean
Application.ScreenUpdating = False
Set OriginalRange = Selection.Range
'start at beginning of document
ActiveDocument.Range(0, 0).Select
strFound = False
If ReplaceChar = "" Then
With Selection.Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = FindChar
.Replacement.Text = ReplaceChar
.Replacement.Font.Name = "Courier New"
.Replacement.Font.Size = 6
.MatchCase = True
End With
If Selection.Find.Execute Then
Selection.Delete Unit:=wdCharacter, Count:=2
Selection.TypeText ("°C")
End If
Else
With Selection.Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = FindChar
.Replacement.Text = ReplaceChar
.Replacement.Font.Name = "Courier New"
.Replacement.Font.Size = 6
.MatchCase = True
.Execute Replace:=wdReplaceAll
End With
End If
OriginalRange.Select
Set OriginalRange = Nothing
Application.ScreenUpdating = True
Selection.Collapse
End Sub
The following code should run over the document, looking for line starts with Simulation Nr. and replace the whole line font with bold and italic.
Sub ReplaceLinesStartWith()
Dim startingWord As String
'the string to search for
startingWord = "Simulation Nr."
Dim myRange As range
'Will change selection to the document start
Set myRange = ActiveDocument.range(ActiveDocument.range.Start, ActiveDocument.range.Start)
myRange.Select
While Selection.End < ActiveDocument.range.End
If Left(Selection.Text, Len(startingWord)) = startingWord Then
With Selection.Font
.Bold = True
.Italic = True
End With
End If
Selection.MoveDown Unit:=wdLine
Selection.Expand wdLine
Wend
End Sub
Note that I hardcoded the string to search for, you can set it as function argument instead.
Related
I have a Word document using font size 8 in which I manually have created some index objects using the shortcut Shift-Alt-X. It might look like this, showing formatting symbols:
some·words·in·bold{·XE·"bold"},·some·in·italic{·XE·"italic"}
Actually, the "XE" is set with font size 11 (my normal standard), but I can't reproduce that here. So I have written a macro which intends to normalize the index object when called from just after the ”}”-sign. It extends the range backwards to include the ”{”-sign and resets the selection to standard values:
Private Sub NormalizeEntry()
Dim rng As Range
Set rng = Selection.Range
With rng
.MoveStartUntil Cset:="{", Count:=-100
.MoveStart Unit:=wdCharacter, Count:=-1
.Select
.Font.Size = 8
.Font.ColorIndex = wdBlack
.Font.Bold = False
.Font.Italic = False
.Select
End With
End Sub
The macro works fine if I apply it after a standard sequence of words enclosed in brackets like
Behold, {here are some words enclosed in brackets} and more words...
("brackets" written with a colored font, which I also can't reproduce here), but it fails when used after an XE-entry. The entry gets selectet all right, but the font is not changed. What am I missing here?
As John advises, you should set the font attributes of the underlying Style to 8pt. As for the bold & italic formatting:
Bold should be applied via the Strong character Style; and
Italic should be applied via the Emphasis character Style.
To revert anything with the wrong format to that of the underlying paragraph Style, simply select the offending content and press Ctrl-Space.
Here's a way of achieving the same thing for all fields via a macro:
Sub FieldReset()
Application.ScreenUpdating = False
Dim Fld As Field, Rng As Range
For Each Fld In ActiveDocument.Fields
With Fld
Set Rng = .Code
With Rng
With .Duplicate
Do While .Fields.Count = 0
.Start = .Start - 1
Loop
Rng.Start = .Start + 1
End With
Do While .Fields.Count = 0
.End = .End + 1
Loop
.Start = .Start - 1
.Font.Reset
End With
End With
Next
Application.ScreenUpdating = True
End Sub
Thank you, Macropod, for your input. However your solution is not what I am looking for, I want to format the field upon insertion.
By experimenting I found a useful solution: Don’t use ActiveDocument.Indexes.MarkEntry, but construct the XE-field yourself using rng.Fields.Add. Here is my result:
Sub TextToNormal(rng As Range)
With rng.Font
.Bold = False
.Italic = False
.Underline = wdUnderlineNone
.StrikeThrough = False
.DoubleStrikeThrough = False
.Color = wdColorAutomatic
.Engrave = False
.Superscript = False
.Subscript = False
End With
End Sub
Function SkipSurroundingSpaces(rng As Range) As Range
With rng
.MoveStartWhile Cset:=" ", Count:=wdForward
.MoveEndWhile Cset:=" ", Count:=wdBackward
.Select
End With
End Function
Sub TestSkipSurroundingSpaces()
Dim rng As Range
Set rng = Selection.Range
SkipSurroundingSpaces rng
End Sub
Sub InsertXEfield()
Dim Xref As String
Dim rng As Range
Set rng = Selection.Range
With rng
SkipSurroundingSpaces rng
Xref = .Text
.Collapse wdCollapseEnd
.Fields.Add Range:=rng, Type:=wdFieldEmpty, _
PreserveFormatting:=False
.Select
.MoveEnd Unit:=wdCharacter, Count:=4
Debug.Print .Start, .End
TextToNormal rng
.MoveStart Unit:=wdCharacter, Count:=2
Debug.Print .Start, .End
.Collapse wdCollapseStart
.InsertAfter "XE """ & Xref & """"
.MoveStart Unit:=wdCharacter, Count:=4
.MoveEnd Unit:=wdCharacter, Count:=-1
.Italic = True
.Bold = True
.Font.ColorIndex = wdViolet
End With
End Sub
Comments:
When selecting a word the range could include a trailing space. This is removed by a call to SkipSurroundingSpaces. Next the selected word is read (actually I take Xref from a form’s inputbox, where it can be changed to something more appropriate, say changing “exoplanets” to “exoplanet”). The range is collapsed to its end and an empty field is inserted. This field might have inherrited formatting from the entry, so it is set back to normal by calling TextToNormal. Then the range is moved into the field (passing by “{·”) and the XE-text is inserted. Finally the range is reduced to include the inserted word only and this word can now be formatted to your heart’s content or as instructed by information from a user form.
(Code and comments updated 2022-06-08)
Knowing many programming languages, I don't have experience with changing very large Word files. Please help. The would be of tremendous help!
Can I do this by macro, VBA or Apache.POI? My first try is VBA (psuedo code), see below.
Requirement 1: How can I delete the first paragraph directly after a 'heading 2' style?
Requirement 2: The paragraph to be deleted should start with a number.
Requirement 3: The paragraph should contain italics text. And have style 'normal' or standard.
Should this be something like (pseudo code):
Sub DeleteParagraphAfterHeading2StaringWithNumberBeingItalics()
heading2Found = False
Dim para As Paragraph
For Each para In ActiveDocument.Paragraphs
If para.Style = wdStyleHeading2
heading2Found = True
ElseIf heading2Found = True Then
txt = para.Range.Text
If ( para.Style = wdStyleNormaltext ) And _
( txt.startsWith( number) ) And _
( para.Range.Font.Italic = True) Then
para.Range.Delete
End If
heading2Found = False
Else
heading2Found = False
End if
Next para
End Sub
Doing this by hand would take many days. So, if you can help,
For example:
Sub Demo()
Application.ScreenUpdating = False
With ActiveDocument.Range
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = ""
.Style = wdStyleHeading2
.Forward = True
.Wrap = wdFindStop
.Format = True
End With
Do While .Find.Execute
With .Paragraphs.Last.Next.Range.Paragraphs.First.Range
If .Style = wdStyleNormal Then
If .Font.Italic = True Then
If IsNumeric(Trim(.Words.First)) Then .Delete
End If
End If
End With
.Collapse wdCollapseEnd
Loop
End With
Application.ScreenUpdating = True
End Sub
I think the code could be like this (requires debugging on real text with real localized styles):
Sub del_para()
With ActiveDocument.Range
.Find.ClearFormatting
.Find.Style = ActiveDocument.Styles("Heading 2") ' adjust style name
Do
If .Find.Execute Then 'find by style
.Move Unit:=wdParagraph
.Expand Unit:=wdParagraph
If (.ListFormat.ListType = wdListOutlineNumbering _
Or .ListFormat.ListType = wdListSimpleNumbering _
Or Left(.Text, 1) Like "[0-9]") _
And .Style = ActiveDocument.Styles("normal") _
And .Font.Italic Then
.Font.ColorIndex = wdRed ' for debug
'.Delete
End If
Else
Exit Do
End If
.Collapse wdCollapseEnd
Loop
End With
End Sub
How can I rename my customVariable in word? I have a Customvaraiable called "Document Number", but I would now like to rename it to _DocumentNumber"
I know I can create a new CustomVariable, delete the old one, but I am then struggling with how to update all the links in the document to the new one.
Edited code:
Sub test()
Dim A As word.Field
Dim FldUpd As String
Dim findText As String
Dim replaceText As String
findText = "Document Number"
replaceText = "_DocumentNumber"
ActiveWindow.View.ShowFieldCodes = False
If ActiveDocument.CustomDocumentProperties(findText).value = "" Then Exit Sub
For Each A In ActiveDocument.Fields
If A.result.Text = ActiveDocument.CustomDocumentProperties(findText).value Then
Call WordProperties.createCustomDocumentProperty(ActiveDocument.name, replaceText, ActiveDocument.CustomDocumentProperties(findText).value)
ActiveWindow.View.ShowFieldCodes = True
A.Select
'DOCPROPERTY "Document number" \* MERGEFORMAT
With Selection.Find
.Text = "DOCPROPERTY*" & findText
.Replacement.Text = "DOCPROPERTY " & replaceText
.Format = True
.MatchCase = False
.MatchWildcards = True
End With
tempBool = Selection.Find.Execute(replace:=wdReplaceAll)
' Refresh fields
ActiveDocument.Fields.update
ActiveWindow.View.ShowFieldCodes = False
If tempBool Then ActiveDocument.CustomDocumentProperties(findText).Delete
End If
Next
End Sub
Edited:
The problem is that the find method does not return true.
You are mixing up two things that must be separate.
First create the new doc property, using ActiveDocument.CustomDocumentProperties.Add
You do this only once, since the doc property exists only once.
Then you replace all existing references to the old doc property to the new one. Something like (excerpts from macro recorder)
' Show field source references (Alt+F9) so you can use Find&Replace
ActiveWindow.View.ShowFieldCodes = True
With Selection.Find
.Text = "DOCPROPERTY Document Number"
.Replacement.Text = "DOCPROPERTY _DocumentNumber"
.Format = False
End With
Selection.Find.Execute Replace:=wdReplaceAll
' Refresh fields
ActiveDocument.Fields.Update
ActiveWindow.View.ShowFieldCodes = False
Then you can delete the old doc property.
Edit: to find and replace in all sections (including header & footer), see
Searching for Text in Header Section of A Word Document
Here is the working code, feel free to improve it:
Sub test()
Dim findText As String
Dim replaceText As String
Dim temp As Variant
findText = "Document Number"
replaceText = "_DocumentNumber"
On Error GoTo doesNotExist
temp = ActiveDocument.CustomDocumentProperties(findText).value
pFindTxt = "DOCPROPERTY*" & findText
pReplaceTxt = "DOCPROPERTY """ & replaceText
ActiveWindow.View.ShowFieldCodes = True
'create the new variable
Call WordProperties.createCustomDocumentProperty(ActiveDocument.name, replaceText, ActiveDocument.CustomDocumentProperties(findText).value)
'Iterate through all story types in the current document
For Each rngStory In ActiveDocument.StoryRanges
'Iterate through all linked stories
Do
SearchAndReplaceInStory rngStory, pFindTxt, pReplaceTxt
On Error Resume Next
Select Case rngStory.StoryType
Case WdStoryType.wdEvenPagesHeaderStory, _
WdStoryType.wdPrimaryHeaderStory, _
WdStoryType.wdEvenPagesFooterStory, _
WdStoryType.wdPrimaryFooterStory, _
WdStoryType.wdFirstPageHeaderStory, _
WdStoryType.wdFirstPageFooterStory
If rngStory.ShapeRange.Count > 0 Then
For Each oShp In rngStory.ShapeRange
If oShp.TextFrame.HasText Then
SearchAndReplaceInStory oShp.TextFrame.TextRange, pFindTxt, pReplaceTxt
End If
Next
End If
Case Else
'Do Nothing
End Select
On Error GoTo 0
'Get next linked story (if any)
Set rngStory = rngStory.NextStoryRange
Loop Until rngStory Is Nothing
Next
' Refresh fields
ActiveDocument.Fields.update
ActiveWindow.View.ShowFieldCodes = False
Exit Sub
doesNotExist:
MsgBox "CustomVariable " & findText & " does not exist"
Exit Sub
End Sub
Public Sub SearchAndReplaceInStory(ByVal rngStory As word.Range, ByVal strSearch As String, ByVal strReplace As String)
With rngStory.Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = strSearch
.Replacement.Text = strReplace
.Wrap = wdFindContinue
.MatchCase = False
.MatchWildcards = True
.Execute replace:=wdReplaceAll
End With
End Sub
I have a word document with tables containing hyperlinks to other word documents, see image below. The word documents are catogorized into groups, i.e 1 table for each group.
My problem is that sometimes people messes around with the formatting, such as adding a newline or removing a newline between the tables(so it becomes 1,2,3,4 newlines instead of 2 as my code requires) or change the order to not be alphabetic(rare and I can live with that).
So finally to my problem, In this case I created a new document PL_xxxx and the table PL does not exist, so it should insert a new table, but with SINGLE newline between tables this get inserted inside another table instead of in between tables.
' Now move up two lines, beyond the table end
Selection.MoveUp Unit:=wdLine, Count:=2
So how can I either ensure that it is always consistence newlines between tables? Is there a way to remove all newlines between tables and then recreate them, and then do the table insert? Or can I somehow loop through all tables in documents? Or is there some other way to make sure that mistakes not like this happens?
So here is my main code:
'here we alter the docout tables
If Not searchAll(dokType) Then
Call addList(dokType, Settings.documentTypeFile)
docNumber = "01"
Else
Below is my code that seach if PL exist, which will return false in this case:
' Moves cursor to the place the given string is found, or replace it
Function searchAll(searchText As String, Optional replaceText As String = "GGG") As Boolean
'default false
searchAll = False
If Not replaceText = "GGG" Then
With ActiveDocument.Range.Find
.Text = searchText
.forward = True
.Wrap = wdFindContinue
.Format = True
.MatchCase = True
.MatchWholeWord = True
.Replacement.Text = replaceText
If .Execute(Replace:=wdReplaceAll) Then
searchAll = True
End If
End With
'just searching
Else
With Selection.Find
.Text = searchText
.forward = True
.Wrap = wdFindContinue
.Format = True
.MatchCase = True
.MatchWholeWord = True
If .Execute Then
searchAll = True
End If
End With
End If
End Function
Here is the code that actually figures out where to place the table and add its, and here is the problem(rewrite to loop through tables instead or modify the moveup function)
Sub addList(tableKey As String, filenameTypes As String)
Dim dict As Object
Dim addAtEnd As Boolean
Dim keyArray As Variant
Dim startSearching As Boolean
Dim element As Variant
'Dictionary with all types
Set dict = getTypes(filenameTypes)
With dict
addAtEnd = False
'extract keys into variant array
keyArray = .keys
startSearching = False
For Each element In keyArray
'looping untill we find the element we want to add
If element = tableKey Then
startSearching = True
End If
'Finding the next table after were we want to insert
If startSearching Then
If searchAll(CStr(element)) Then
addAtEnd = False
Exit For
Else
addAtEnd = True
End If
End If
Next
If addAtEnd Then
Selection.EndKey Unit:=wdStory
Else
Call HelpFunctions.moveCursorUp(CStr(element))
End If
Call addTable("UT", tableKey, .item(tableKey), Settings.docUtPath)
End With
Set dict = Nothing
End Sub
And finally the move up function which then obviously moves up to much and inside the next table.
'move cursor up
Function moveCursorUp(searchText As String)
If Not searchAll(searchText) Then
MsgBox "Failed to move cursor"
Else
'Selection.Tables(1).Select
If Selection.Information(wdWithInTable) Then
Selection.Tables(1).Range.Select
Selection.Collapse 1
' Now move up two lines, beyond the table end
Selection.MoveUp Unit:=wdLine, Count:=2
End If
'Selection.Collapse WdCollapseDirection.wdCollapseStart
End If
End Function
And here is the addtable code which basically has an empty tabley stored in a seperate file.
Function addTable(typeOfTable As String, category As String, description As String, templateFolder As String)
'Insert out table
If UCase(typeOfTable) = "UT" Then
Selection.InsertFile FileName:=templateFolder + "\Doklistut.doc", Range:="", _
ConfirmConversions:=False, link:=False, Attachment:=False
'insert inn table
ElseIf UCase(typeOfTable) = "INN" Then
Selection.InsertFile FileName:=templateFolder + "\Doklistinn.doc", Range:="", _
ConfirmConversions:=False, link:=False, Attachment:=False
Else
MsgBox "wrong argument given: either inn or ut is allowed"
Exit Function
End If
'Replace the DT with the category
If Not searchAll("DT", category) Then
MsgBox "Failed to replace category in table"
End If
'Replace the Dokumenttype with the category
If Not searchAll("Dokumenttype", description) Then
MsgBox "Failed to replace document type in table"
End If
End Function
So thanks to all the input I have now revised the code totally and it is now working as desired, It can probably be improved, especially the selection method.
Sub addList(tableKey As String, tableDescription As String)
Selection.EndKey Unit:=wdStory
Call addTable(tableKey, tableDescription)
Call SortTables
End Sub
Sub Deleemptylines()
Selection.Find.ClearFormatting
Selection.Find.Replacement.ClearFormatting
With Selection.Find
.Text = "^p"
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindContinue
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchByte = False
.MatchAllWordForms = False
.MatchSoundsLike = False
.MatchWildcards = False
.MatchFuzzy = False
End With
Selection.Find.Execute Replace:=wdReplaceAll
End Sub
Sub SortTables()
Dim i As Long
Dim iMin As Long
Dim iMax As Long
Dim blnSwapped As Boolean
Call Deleemptylines
iMin = 1
iMax = ActiveDocument.Tables.Count - 1
Do
blnSwapped = False
For i = iMin To iMax
If ActiveDocument.Tables(i).Cell(1, 1).Range.Text > ActiveDocument.Tables(i + 1).Cell(1, 1).Range.Text Then
ActiveDocument.Tables(i).Range.Cut
ActiveDocument.Tables(i).Select
Selection.Collapse WdCollapseDirection.wdCollapseEnd
Selection.Paragraphs.Add
Selection.Paragraphs.Add
Selection.MoveDown Unit:=wdLine, Count:=1
Selection.MoveUp Unit:=wdLine, Count:=1
Selection.Paste
blnSwapped = True
End If
Next i
iMax = iMax - 1
Loop Until Not blnSwapped
Call Deleemptylines
End Sub
Function addTable(category As String, description As String)
'Insert out table
Selection.InsertFile FileName:=Settings.docUtPath + "\Doklistut.doc", Range:="", _
ConfirmConversions:=False, link:=False, Attachment:=False
'Replace the DT with the category
If Not searchAll("DT", category) Then
MsgBox "Failed to replace category in table"
End If
'Replace the Dokumenttype with the category
If Not searchAll("Dokumenttype", description) Then
MsgBox "Failed to replace document type in table"
End If
End Function
The following shows pattern of a very long document:
<heading1>
<numberedlist>
<heading2>
<numberedlist>
<heading3>
<numberedlist>
When I use Document.Lists I get all the lists in the document. When Iterate using Document.Paragraphs where Document.Paragraphs(i).Style = "Heading 1" I get all the headings.
But What I want is the List (not paragraph of the list) which is immediately after "Heading 1"
Assuming that your document can look like one on the picture below:
Using this proposed code you would be able to select first list (immediate after heading) and other similar lists located below Heading but not the second (there is additional paragraph between heading and list- for that situation see additional comments inside code).
Sub List_after_Heading()
Dim rngLIST As Range
Set rngLIST = ActiveDocument.Content
With rngLIST.Find
.Style = "Heading 1" '<--change into your Heading name
.Forward = True
.Wrap = wdFindStop
End With
Do
rngLIST.Find.Execute
If rngLIST.Find.Found Then
'I assume that list start in NEXT paragraph, if not, it wouldn't be found
'or you need to change part of line into .Next.Next paragraphs,
'alternatively some looping would be needed here
'we check if paragraph next to Heading contains a list
If rngLIST.Paragraphs(1).Next.Range.ListParagraphs.Count > 0 Then
'we have the list, but it's not easy to select at once
Dim iLIST As List
For Each iLIST In ActiveDocument.Lists
If iLIST.Range.Start = rngLIST.Paragraphs(1).Next.Range.Start Then
'here we have it... selected
iLIST.Range.Select
'or any other of your code here
End If
Next
End If
End If
Loop While rngLIST.Find.Found
End Sub
I use bookmarks to identify the Headings and then simply return the text between them. But I am not sure by what you mean by But What I want is the List (not paragraph of the list)
ScreenShot
Code
Option Explicit
Sub Sample()
Dim MyRange As Range
Selection.HomeKey Unit:=wdStory
On Error Resume Next
ActiveDocument.Bookmarks("MYStartBookMark").Delete
ActiveDocument.Bookmarks("MYEndBookMark").Delete
On Error GoTo 0
'~~> Find Heading 1
With Selection.Find
.ClearFormatting
.Style = ActiveDocument.Styles("Heading 1")
.Text = ""
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindContinue
.Format = True
.Execute
End With
'~~> Move one space to the right
Selection.MoveRight Unit:=wdCharacter, Count:=1
'~~> Insert the start Book mark
With ActiveDocument.Bookmarks
.Add Range:=Selection.Range, Name:="MYStartBookMark"
.DefaultSorting = wdSortByName
.ShowHidden = False
End With
'~~> Find Heading 2
With Selection.Find
.ClearFormatting
.Style = ActiveDocument.Styles("Heading 2")
.Text = ""
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindContinue
.Format = True
.Execute
End With
'~~> Move one space to the left
Selection.MoveLeft Unit:=wdCharacter, Count:=1
'~~> Insert the end Book mark
With ActiveDocument.Bookmarks
.Add Range:=Selection.Range, Name:="MYEndBookMark"
.DefaultSorting = wdSortByName
.ShowHidden = False
End With
'~~> Identify the range between the Start BookMark and End BookMark
Set MyRange = ActiveDocument.Range
MyRange.Start = MyRange.Bookmarks("MYStartBookMark").Range.End
MyRange.End = MyRange.Bookmarks("MYEndBookMark").Range.Start
'~~> This gives you that text
Debug.Print MyRange.Text
'~~> Delete the BookMarks
On Error Resume Next
ActiveDocument.Bookmarks("MYStartBookMark").Delete
ActiveDocument.Bookmarks("MYEndBookMark").Delete
On Error GoTo 0
End Sub
Result
OTHER TESTS
One might say that what if we do not know what the next heading is? Which is a fair point as we can have two more scenarios. Let me cover them together
After Heading 1, we have Heading 3
The last Heading in a document is Heading 1 and after that there are no headings.
MODIFIED CODE
Option Explicit
Sub Sample()
Dim MyRange As Range
Dim MyArray
Dim strOriginal As String, strTemp As String
Dim numDiff As Long, i As Long, NextHd As Long
Dim NoNextHeading As Boolean
Selection.HomeKey Unit:=wdStory
On Error Resume Next
ActiveDocument.Bookmarks("MYStartBookMark").Delete
ActiveDocument.Bookmarks("MYEndBookMark").Delete
On Error GoTo 0
'~~> Get all the headings in the array
NoNextHeading = True
For i = LBound(MyArray) To UBound(MyArray)
strOriginal = RTrim$(MyArray(i))
strTemp = LTrim$(strOriginal)
numDiff = Len(strOriginal) - Len(strTemp)
numDiff = (numDiff / 2) + 1
'~~> If heading one is found and it is not the last heading
'~~> in the array then find what is the next heading
If numDiff = 1 And i <> UBound(MyArray) Then
strOriginal = RTrim$(MyArray(i + 1))
strTemp = LTrim$(strOriginal)
numDiff = Len(strOriginal) - Len(strTemp)
numDiff = (numDiff / 2) + 1
NextHd = numDiff
NoNextHeading = False
Exit For
End If
Next i
'~~> Find Heading 1
With Selection.Find
.ClearFormatting
.Style = ActiveDocument.Styles("Heading 1")
.Text = ""
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindContinue
.Format = True
.Execute
End With
'~~> Move one space to the right
Selection.MoveRight Unit:=wdCharacter, Count:=1
'~~> Insert the start Book mark
With ActiveDocument.Bookmarks
.Add Range:=Selection.Range, Name:="MYStartBookMark"
.DefaultSorting = wdSortByName
.ShowHidden = False
End With
If NoNextHeading = False Then
'~~> Find Heading NextHd
With Selection.Find
.ClearFormatting
.Style = ActiveDocument.Styles("Heading " & NextHd)
.Text = ""
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindContinue
.Format = True
.Execute
End With
'~~> Move one space to the left
Selection.MoveLeft Unit:=wdCharacter, Count:=1
Else
'~~> Move to the end of the document
ActiveDocument.Characters.Last.Select
Selection.Collapse
End If
'~~> Insert the end Book mark
With ActiveDocument.Bookmarks
.Add Range:=Selection.Range, Name:="MYEndBookMark"
.DefaultSorting = wdSortByName
.ShowHidden = False
End With
'~~> Identify the range between the Start Book Mark and End BookMark
Set MyRange = ActiveDocument.Range
MyRange.Start = MyRange.Bookmarks("MYStartBookMark").Range.End
MyRange.End = MyRange.Bookmarks("MYEndBookMark").Range.Start
'~~> This give you that text
Debug.Print MyRange.Text
'~~> Delete the BookMarks
On Error Resume Next
ActiveDocument.Bookmarks("MYStartBookMark").Delete
ActiveDocument.Bookmarks("MYEndBookMark").Delete
On Error GoTo 0
End Sub