Removing characters from the start of multiple style paragraph in VBA for Word - vba

This is a follow-up question to my question (How to search/find for multiple format styles in VBA for Word?). This time instead of inserting a text to the beginning of each heading, we want to remove a few characters from the start of each heading after navigating to a heading titled 'Appendix'.
Trying to get rid of the first number along with the following white space or a period for multi-style paragraphs. For example, we would have headings with '4 Appendix A', '5.1 Intro', '10.2.3 Glossary...', which would be renamed to 'Appendix A', '1 Intro', '2.3 Glossary...'.
I removed the Selection.TypeText Text:=" *Test* " Selection.MoveStart wdParagraph, 1 lines after navigating to the Appendix section and replaced Selection.TypeText Text:=" *Test* " in the If found Then statement with the code seen below.
`If found Then
Selection.HomeKey Unit:=wdLine
If IsNumeric(Selection.Characters(2) = True) Then
Selection.Delete Unit:=wdCharacter, Count:=3
Selection.MoveStart wdParagraph, 1
ElseIf IsNumeric(Selection.Characters(1) = True) Then
Selection.Delete Unit:=wdCharacter, Count:=2
Selection.MoveStart wdParagraph, 1
Else
Selection.MoveStart wdParagraph, 1
End If
End If`
Getting run-time error '5941' - The requested member of the collection does not exist. If IsNumeric(Selection.Characters(2) = True) Then seems to be the cause of the error. If I change the '2' to a '1' and Count:=3 to Count:=2 in the If statement and '1' to a '2' and Count:=2 to Count:=3 in theElseIf, then the code is executable. This is a problem because it doesn't recognize theElseIf` and only deletes 2 characters for a double-digit number leaving an unwanted white-space or period, i.e., '.2.3 Glossary...' or ' Appendix G'.

The reason for the error 5941 due to Characters(2). This is not doing what you imagine. That gets the second character, only, from the selection, not two characters. And the selection is a blinking insertion point so does not contain two characters. The error says: You're telling me to get the second character, but there aren't two characters, so I can't give you what you require.
Another problem in that line (that you're not seeing, yet): The parenthesis should be before the =, not after the True: If IsNumeric(Selection.Characters(2)) = True.
Since it's necessary to test multiple characters, the selection (or Range) needs to be extended. Word VBA offers a number of "Move" methods; the equivalent to holding Shift and pressing right-arrow on the keyboard is MoveEnd, and there are variations of this such as MoveEndWhile and MoveEndUntil that allow you to specify conditions. Optionally, these can return the number of characters that were moved (as done in the code below).
The following approach uses MoveEndWhile to first get numeric characters (until the next is no longer numeric): MoveEndWhile("0123456789", wdForward)... Followed by extending until the next character is no longer a ..
This Range is then deleted. (There's also a Debug.Print line in there to print out the content of the Range and the number of characters moved, in case that information interests you - just remove the comment mark ').
Note that I've included the entire code, in case others are interested in seeing it in its entirety. The parts from the previous question that are no longer relevant have been removed. You'll find the new part marked as '''NEW CODE HERE.
Sub AppendixFix()
' Declaring variables
Dim multiStyles As String, i As Integer
Dim aStyleList As Variant
Dim counter As Long, s As String, found As Boolean
Dim rngStart As Range
multiStyles = "Heading 1,Heading 2,Heading 3,Heading 4,Heading 5,Heading 6,Heading 7,Heading 8,Heading 9"
aStyleList = Split(multiStyles, ",")
' Start at the top of document and clear find formatting
Selection.HomeKey Unit:=wdStory
Selection.Find.ClearFormatting
' Navigate to Appendix section
Selection.Find.style = ActiveDocument.styles("Heading 1")
With Selection.Find
.Text = "Appendix"
.Forward = True
.wrap = wdFindStop
.Format = True
.Execute
End With
Selection.HomeKey Unit:=wdLine
Set rngStart = Selection.Range.Duplicate
' Loop through all the styles in the list
For counter = LBound(aStyleList) To UBound(aStyleList)
'Loop as long as the style is found
Do
s = aStyleList(counter)
With Selection.Find
.style = ActiveDocument.styles(s)
.Text = "^p"
.Forward = True
.wrap = wdFindStop
.Format = True
found = .Execute
End With
'''NEW CODE HERE
Dim rngStartOfLine As Range
Dim charsMovedNumeric As Long, charsMovedDot
If found Then
Selection.HomeKey Unit:=wdLine
Set rngStartOfLine = Selection.Range
charsMovedNumeric = rngStartOfLine.MoveEndWhile("0123456789", wdForward)
charsMovedDot = rngStartOfLine.MoveEndWhile(".")
'Debug.Print rngStartOfLine, charsMovedNumeric, charsMovedDot
rngStartOfLine.Delete
Selection.MoveStart wdParagraph, 1
End If
'''END OF NEW CODE
If Selection.Start = ActiveDocument.content.End - 1 Then
'End of Document, then loop to next style in list
Exit For
End If
Loop Until found = False
'start back at the Appendix for the next style
rngStart.Select
Next
End Sub

Related

Replace all uppercase text to smallcaps AND wdTitleSentence

I'm stuck with this problem for the past two days and I can't find a way to overcome it.
I've a document (400 pages) where I want to replace ALL the uppercase words to SmallCaps AND set the text as "title sentence".
When I register a macro, I found the commands that I need:
Selection.Range.Case = wdTitleSentence
Selection.Font.SmallCaps = wdToggle
The problem is that I can't find a way to apply these commands only to the uppercase words and NOT to the selected text.
You could try using a wildcard search, though you'll need to be careful how you specify it other wise you could change every capital letter in the document to small caps.
Sub ConvertUpperCase()
Dim findRange As Range
Set findRange = ActiveDocument.Content
With findRange.Find
.ClearFormatting
'find at least two consecutive capital letters
.Text = "[A-Z]{2,}"
.MatchWildcards = True
Do While .Execute = True
With findRange
.Case = wdTitleSentence
.Font.SmallCaps = True
.Collapse wdCollapseEnd
End With
Loop
End With
End Sub

How to search from a certain point in a document down and end the search?

I have the following code that searches for a certain point in a document and creates a search range until the end of the document. Then within that range it removes the paragraph following entirely bold paragraphs (subheadings), ignoring any styles that aren't Normal and aren't in a table. However, it seems to search the entire document (i.e. the beginning as well). How can I make it only search the range (i.e. from where I've positioned the cursor down to the end of the document)?
Dim aPara As Paragraph
Dim oSearchRange As Range
With Selection.Find
.Text = "Dear "
End With
Selection.MoveDown Unit:=wdParagraph, Count:=4
Set oSearchRange = Selection.Range
oSearchRange.End = ActiveDocument.Content.End
oSearchRange.MoveEnd wdParagraph, -1
For Each aPara In oSearchRange.Paragraphs
If aPara.Range.Font.Bold = True And aPara.Range.Next.Style = ActiveDocument.Styles("Normal") And Not aPara.Range.Next.Information(wdWithInTable) Then aPara.Range.Next.Delete
Next aPara
Thanks
I needed to add .Execute after the "Dear " search, thanks to Teamothy (:

MS Word: Create Table of Figures with two SEQIdentifiers in it via VBA

My goal is to create a TOC with two SEQIdentifiers in it.
It is described and answered HERE, though the given answer is manually configured, and I want to activate it with a macro.
Brief description
I have a sequential Figures throughout the document which can be gathered with Table of figures {SEQ \c "Figure"}.
The Figure structure is as follows:
Figure {STYLEREF 1 \s}-{SEQ Figure \*Arabic \s 1} - Result with 'Figure 1-1' for example.
The client request is to add "Point Figure", meaning between two figures: Figure 1-1 and Figure 1-2 the client can add Figure 1-1.A, Figure 1-1.B and so on.
Here is how I've initially created the sturcture:
Figure {STYLEREF 1 \s}-{SEQ Figure \*Arabic \c}.{SEQ PointFigure \* Alphabetic \s 1}.
The problem now is that I can not include both of them in a single Table of Figures.
Trying to implement the given answer:
So, my next approach was starting to implement the answer given in the link above.
The given answer by the way is as follow:
Bookmark the seq field with a special name - in the example it's tablea
refer to the reference by { SEQ Table \r { REF tablea } }
Here is my code followed by explanation and my problem:
Sub createPointFigure()
Dim rng As Range
Dim fld As Field
Dim searchText As String
Set rng = Selection.Range
rng.InsertAfter "Figure "
rng.Collapse wdCollapseEnd
Set fld = rng.Fields.Add(rng, wdFieldEmpty, "StyleRef 1 \s", False)
Set rng = fld.result
'Move focus after the inserted field
rng.Collapse wdCollapseEnd
rng.MoveStart wdCharacter, 1
rng.InsertAfter "-"
rng.Collapse wdCollapseEnd
rng.Fields.Add rng, wdFieldEmpty, "SEQ Figure \c", False
' select the entire inserted text
Selection.MoveRight wdWord, 4, wdExtend
searchText = Selection.Text
Set rng = Selection.Range
' Search for the specific figure in text
Selection.Collapse wdCollapseStart
Dim found As Boolean
found = False
While Not found And Selection.Start <> 1
findText searchText, False
For Each fld In Selection.Fields
If fld.Type = wdFieldSequence Then
' look for the original seq field
If InStr(1, fld.Code.Text, "\s 1", vbTextCompare) Then
found = True
Exit For
End If
End If
Next fld
If found Then
ActiveDocument.Bookmarks.Add Selection.Text, Selection
Else
' Collapse to the beginning and keep looking for the next one
Selection.Collapse wdCollapseStart
End If
Wend
End Sub
The findText method:
Sub findText(searchParam As String, forwardDirection)
With Selection.find
.ClearFormatting
.Text = searchParam
.Forward = forwardDirection
.Wrap = wdFindStop
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchKashida = False
.MatchDiacritics = False
.MatchAlefHamza = False
.MatchControl = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
.Execute
End With
End Sub
Explanation:
Temporary create the closest Figure text
Search backward until finding the appropriate figure (keep looking if found a sequence field with \c).
Once found, create a new bookmark with the name
Construct the field as the answer suggests (Not implemented in the code)
Problems
Testing fails in the insert bookmark line:
ActiveDocument.Bookmarks.Add Selection.Text, Selection
Apparently, Bookmark cannot contain numbers and symbols in it.
How can I distinguish a reusable bookmark? For the next time I'll Create this Figure structure, I would like to reuse the same Bookmark.
All this work has huge overhead. Is there a simpler solution to accomplish my goal?
Thanks.
Thanks to #CindyMeister guidance, here is an elegant answer for my problem.
Point Figure configuration:
Figure {STYLEREF 1 \s}-{SEQ Figure \c}.{SEQ PointFigure \* Alphabetic \s 1}. Figure Text *Style Separator* {TC "{STYLEREF "Figure Title"}" \f F}
Table of Figures Configuration:
{TOC \f F \c "Figure"}
Remarks:
Figure style in my example is configured as "Figure Title"
The {TC} must be of a different style in order for STYLEREF to work.
For that I've used Style Separator (Ctrl + Alt + Return). Character style is another option I think.
All {} brackets in the code examples are Word Fields (Ctrl + F9)
I inserted the Point Figure text as an AutoText, which is added via Macro.
In order to achieve unique point numbering for each 'Figure 1-1' text, I've added a reset field before each one: {SEQ PointFigure \h \r 0}

Change the case of a Range text and type it

Possible scenario, let say we created a Range Object containing the following line:
Speculative BUY, FV: EGP19.59
Now I want to split the Range Object into two parts by ", " as delimiter so that the given Range will change into two Ranges containing "Speculative BUY" and ", FV: EGP19.59" (Two separate range).
Now I need to change the case of only the first range containing "Speculative BUY" into "Speculative Buy" using:
.Case = wdTitleWord
Previously I am using .Find to change the Ranges in the following code (this is not complete code as it is only changing the Range R, not splitting it into two):
Sub Range_into_Ranges()
selection.EndKey Unit:=wdLine
selection.MoveUp Unit:=wdParagraph, COUNT:=1, Extend:=wdExtend
Dim R, F As Word.Range
Set R = selection.Range
Set F = R.Duplicate
With F.Find
.Text = ", "
.Forward = True
.Wrap = wdFindStop
.Execute
End With
If F.Find.Found Then
R.SetRange Start:=R.Start, _
End:=F.Start
R.Case = wdTitleWord
Else
End If
End Sub
Note: There may be other ways of producing the same results. you are free to advice me another simple code.
You can assign a case to a Range using the WdCharacterCase enumeration. For title case:
R.Case = wdTitleWord
Put into the context of your sample code, something like as follows. I did some tweaking:
My version assumes you want to work with the paragraph where the selection currently is, which is why I commented out your first two lines
In VBA you need to declare the data type of every variable, otherwise it's a Variant. So: Dim R As Word.Range
VBA provides the Split function to divide up a string according to a delimiter. I use this to get the term to search, so that you can get the Range directly
I found when setting Title Case on text that has ALL CAPS that it doesn't reduce upper case to lower case. But first applying lower case, then title case, does work.
Sample code
Sub Range_into_Ranges()
' Selection.EndKey Unit:=wdLine
' Selection.MoveUp Unit:=wdParagraph, Count:=1, Extend:=wdExtend
Dim R As word.Range, F As word.Range
Dim sTerm As String, bFound As Boolean
Set R = Selection.Paragraphs(1).Range
R.MoveEnd wdCharacter, -1 'Trim off the paragraph mark
sTerm = R.Text
sTerm = Split(sTerm, ",")(0)
Set F = R.Duplicate
With F.Find
.Text = sTerm
.Forward = True
.wrap = wdFindStop
bFound = .Execute
End With
If bFound Then
F.Case = wdLowerCase
F.Case = wdTitleWord
Else
End If
End Sub

Use VBA with Powerpoint to Search titles in a Word Doc and Copy Text into another Word Document

I'm working on a Powerpoint slide, where I few texts are listed. I have to search for these texts in a Word Document which has a lot of Headings and Texts. After I find the title text, I need to copy the text under the Heading and paste in a new document.
Basically, the VBA coding has to be done in the Powerpoint VBA, with two documents in the background for searching text and pasting it in another.
I've opened the word doc. But searching the text in it and selecting it for copying to another document is what I've not been able to do. Kindly help me.
I see. The following is not exactly elegant since it uses Selection which I always try to avoid but it is the only way I know to achieve such a thing.
Disclaimer 1: this is made in Word VBA, so you will need a slight adaption, like set a reference to Word, use a wrdApp = New Word.Application object and declare doc and newdoc explicitely as Word.Document.
Disclaimer 2: Since you search for text instead of the respective heading, beware that this will find the first occurence of that text so you better not have the same text in several chapters. ;-)
Disclaimer 3: I cannot paste anymore! :-( My clipboard is set, it pastes elsewhere but I just cannot paste in here.
Code follows with first edit, hopefully in a minute...
Edit: yepp, pasting works again. :-)
Sub FindChapter()
Dim doc As Document, newdoc As Document
Dim startrange As Long, endrange As Long
Dim HeadingToFind As String, ChapterToFind As String
ChapterToFind = "zgasfdiukzfdggsdaf" 'just for testing
Set doc = ActiveDocument
Set newdoc = Documents.Add
doc.Activate
Selection.HomeKey unit:=wdStory
With Selection
With .Find
.ClearFormatting
.Text = ChapterToFind
.MatchWildcards = False
.MatchCase = True
.Execute
End With
If .Find.Found Then
'**********
'Find preceding heading to know where chapter starts
'**********
.Collapse wdCollapseStart
With .Find
.Text = ""
.Style = "Heading 1"
.Forward = False
.Execute
If Not .Found Then
MsgBox "Could not find chapter heading"
Exit Sub
End If
End With
.MoveDown Count:=1
.HomeKey unit:=wdLine
startrange = .Start
'*********
'Find next heading to know where chapter ends
'*********
.Find.Forward = True
.Find.Execute
.Collapse wdCollapseStart
.MoveUp Count:=1
.EndKey unit:=wdLine
endrange = .End
doc.Range(startrange, endrange).Copy
newdoc.Content.Paste
newdoc.SaveAs2 doc.Path & "\" & HeadingToFind & ".docx", wdFormatFlatXML
Else
MsgBox "Chapter not found"
End If
End With
End Sub
Edit: If you need to search for a "feature" that will be in some table in column 1 with the description in column 2 and you need that description in a new doc, try this:
Sub FindFeature()
Dim doc As Document, newdoc As Document
Dim FeatureToFind As String
Dim ro As Long, tbl As Table
FeatureToFind = "zgasfdiukzfdggsdaf" 'just for testing
Set doc = ActiveDocument
Set newdoc = Documents.Add
doc.Activate
Selection.HomeKey unit:=wdStory
With Selection
With .Find
.ClearFormatting
.Text = FeatureToFind
.MatchWildcards = False
.MatchCase = True
.Execute
End With
If .Find.Found Then
Set tbl = Selection.Tables(1)
ro = Selection.Cells(1).RowIndex
tbl.Cell(ro, 2).Range.Copy
newdoc.Range.Paste
End If
End With
End Sub
Edit: Slight adaptation so you can paste without overwriting existing content in newdoc:
Instead of newdoc.Range.Paste just use something along the line of this:
Dim ran As Range
Set ran = newdoc.Range
ran.Start = ran.End
ran.Paste