Finding Endnote number with wdRestartSection NumberingRule - vba

I am writing a VBA script to convert endnotes to plain text. This is fairly straightforward when the endnotes have continuous numbers (copy all the end notes to the end of the text, number them using the index, and replace all the references with the indexes).
In this case, however, the endnote numbers are configured to reset every section (NumberingRule=wdRestartSection). This means the index is not the number. I've tried to get the number using endnote.Reference.Text, but this is empty. I haven't found anywhere in the object model that has the actual number for each Endnote.
Is this information available?
Is there a way to walk Endnotes per-section rather than for the entire document so that I could track the index myself?
I'm currently trying to fetch it this way:
For Each objEndnote In ActiveDocument.Endnotes
print(objEndnote.Reference.Text)
Next
This just prints empty strings.

Looks like there is no number per section - weird. So you have to count it yourself per section:
Option Explicit
Sub getAllEndnotesWithNumbers()
Dim e As Endnote, section As Long, eCounter As Long
For Each e In ThisDocument.Endnotes
If section <> endnoteSection(e) Then
section = endnoteSection(e)
eCounter = 1
Debug.Print "--- Section " & section & " ----------"
End If
Debug.Print eCounter, e.Range.Text
eCounter = eCounter + 1
Next
End Sub
Private Function endnoteSection(e As Endnote) As Long
endnoteSection = e.Range.Sections(1).Index
End Function

Related

Counting words in Word document, including footnores

I periodically receive long documents that include footnotes and am trying to find a way using VBA to count the number of words on each page, including footnotes. It doesn't matter if a footnote spills over onto the next page, I just the word count including footnotes that are anchored on the page.
I have a macro that correctly counts the number of words in the body of the text, using the command:
WordCount = ActiveDocument.Range(Start:=pos1, End:=pos2).ComputeStatistics(wdStatisticWords)
The variables pos1 and pos2 have been set to the first and last characters of the page being counted.
However, when I add the True parameter to ComputeStatistics(wdStatisticWords, True), to IncludeFootnotesAndEndnotes, as in:
WordCount = ActiveDocument.Range(Start:=pos1, End:=pos2).ComputeStatistics(wdStatisticWords, True)
it doesn't work, giving an error that there are too many parameters. It appears that when using a Range, the IncludeFootnotesAndEndnotes parameter is not available.
How do you count the words within footnotes contained in a range?
I think what you will need to do is iterate into each of the StoryRanges and update a counter. Here is a small example that should serve as an example, however, you will likely need to tweak it for your specific case (review my note about the enum for StoryRanges)
Here's the code:
Public Sub Count_All_Words()
Dim Story_Ranges As Variant: Set Story_Ranges = ActiveDocument.StoryRanges
Dim Story_Range As Object
Dim WordCount As Long
'Loop through each story range and only include the footer and Main story to the word count
For Each Story_Range In Story_Ranges
'You may need to check additional types, lookup the enumerations for StoryType here:
'https://msdn.microsoft.com/en-us/library/bb238219(v=office.12).aspx
If Story_Range.StoryType = wdMainTextStory Or Story_Range.StoryType = wdFootnoteSeparatorStory Then
'Add to the word count
WordCount = WordCount + Story_Range.ComputeStatistics(wdStatisticWords)
End If
Next
Debug.Print "The word count is: " & WordCount
End Sub

Call macros based on characters of a filename

How can I call macros based on the left n characters of a filename?
Details:
I get emailed many files per month whose names contain a few characters followed by a date or serial number.
For example
- Accounts receivable files are named ARDET 25-01-16.xls, ARDET 19-01-16.xls , ARDET 31-12-15.xls and so on
- Invoicing files are named Bkg_Inv_01.xls, Bkg_Inv_02.xls, Bkg_Inv_03.xls and so on
I have recorded various macros to run on these files. For example, I have Sub ARDET() and Sub Bkg_Inv() to handle the above files.
I want to create a single macro to call the above Subs if the first 5 characters of the filename matches certain text.
The code I am looking for needs to be roughly in the following syntax:
Sub Call_Macro_if_leftn_is()
' Making variables
This_File_name = Currently open file's filename
n = InputBox("Enter the total number of characters from the left of the filename to match")
y = Left n characters of This_File_name
'If Then statements to call other macros
If y = ARDET
Call ARDET()
Else if y = Bkg_I
Call Bkg_Inv()
Else if y = PDC_I
Call PDC_Inv()
Else Msgbox "Filename does not match specified characters"
End Sub
I'd try a set-up something like this:
Sub RunCodeBasedOnFileName()
Dim fileID As String
fileID = VBA.Left$(ThisWorkbook.Name, 5)
If fileID = "ARDET" Then
ARDET
ElseIf fileID = "Bkg_I" Then
Bkg_I
ElseIf fileID = "PDC_I" Then
PDC_I
Else
MsgBox "This file is of unknown origin!"
End If
End Sub
Sub ARDET()
'Do stuff
End Sub
Sub Bkg_I()
'Do stuff
End Sub
Sub PDC_I()
'Do stuff
End Sub
You don't need to use Call or have the parentheses () when calling a sub
I'd avoid getting people to input the first 5 characters - instead get it programmatically
The only bit I am unclear about is where you are running this code from and how you are iterating over the files that you are sent?
Where I have ThisWorkBook this requires the code to be running in the actual file. I think you'll need to modify that e.g. you loop over a bunch of files in a folder and access the filename that way.
Thanks Alex. I will test your code and tell you how it works.
I get such files through email atleast 10 times a day. I run my macros on files before I store them in folders named by month and category of file.
But coming to think of it, your idea of iterating through files in a folder is great ! Could you have the same code iterate over all files in a folder, and preferably, its sub folders as well?
My files are stored in folders in a hierarchy that goes like
- "C:\Dropbox\Work\2016\Jan\ARDET Jan" or
- "C:\Dropbox\Work\2016\Jan\BkgInv Jan"

Word 2010 VBA macro to restart numbered lists

I have a Word 2010 document with a lot of lists that were copied from another document. Unfortunately, when I copied the lists into my document they do not start at 1 anymore as they did in the orginial but are continuing from the previous lists leading up to chaos in my document.
I need my macro to run along all the numbered lists in my document and restarts each list at 1. I tried this with listformat.applylisttemplate but when calling my lists with "For Each li In ActiveDocument.Lists" I could not use the listformat function. See my code snippet below.
Set temp3 = wrdApp.ListGalleries(wdNumberGallery).ListTemplates(1).ListLevels(1)
With temp3
.StartAt = 1
End With
For Each li In ActiveDocument.Lists
li.Range.ListFormat.ApplyListTemplate ListTemplate:=temp3
Next
Obviously I would like something in the form of:
For Each li In ActiveDocument.Lists
li. => restart list count here
Next
Can anyone help? Thanks!
Addition: my current text looks like below and I'm trying to get the macro to restart each list with 1 in Word:
INPUT:
Sometext
3. TextA
4. TextB
5. TextC
6. TextD
Some other text
21. Text q
22. Text w
23. Text e
OUTPUT after macro:
1. TextA
2. TextB
3. TextC
4. TextD
Some other text
1. Text q
2. Text w
3. Text e
I don't have an example to try this on but give it a try, perhaps it will work?
Sub ListRestart()
For Each li In ListGalleries(wdNumberGallery).ListTemplates
li.ListLevels(1).StartAt = 1
Next
End Sub
Edit:
I agree, the above doesn't do the trick. The following will identify the correct paragraph where we want to reset the numbering. However, I cannot figure out how to reset the numbering from there. Perhaps that will get someone else closer to the answer?
Sub ListRestart()
' for each paragraph
' If this paragraph is a list (ListType = 3) and last paragraph was not (ListType = 0) then restart numbering
Dim n As Integer, lastListType As Integer
For Each myPara In ActiveDocument.Paragraphs
n = n + 1
'Debug.Print n & myPara.Range.Text & " ListType: " & myPara.Range.ListFormat.ListType
If myPara.Range.ListFormat.ListType = 3 Then
If lastListType = 0 Then
Debug.Print n & " " & myPara.Range.Text & " Reset numbering here"
End If
End If
lastListType = myPara.Range.ListFormat.ListType
Next
End Sub
Hi I have created a macro here that does exactly what you want.
You need to make the numbered lists as a certain style first. This is to make sure that the macro changes only the lists you need to change.
https://sites.google.com/site/anvilsoup/word/fix-numbered-items
How it works
I've chosen to use a reasonable method of determining when to restart lists: If the previous paragraph isn't a list item, then this paragraph must be a new list!
This logic is what most people use when starting a new list. It's sensible and conventional.
NOTE: If you need to have an unnumbered paragraph nestled within a list, you should consider using line breaks (SHIFT-ENTER) instead of paragraph breaks. Using line breaks will also ensure that indenting is preserved. Don't do strange things like turn off numbering for that paragraph. Technically this text is part of the same numbered item so it should be in the same paragraph.

What defines a sentence in MS-Word?

I know that the sentences collection is just a just a bunch of ranges, but I have not been able to determine exactly what criteria are used to decide where those ranges begin and end. I have been able to determine that a period (.) a question mark (?) or an exclamation point (!) followed by one or more spaces is the end of a sentence and that the spaces are included in the sentence range. I have also determined that if there are no spaces between what you and I would consider two sentences MS-Word considers it as only one sentence.
The problem is when you start putting in things like tabs, page breaks, new line characters etc. things become unclear. Can anyone explain precisely or point me to some reference material what criteria MS-Word uses to decide where one sentence ends and another begins?
Seems to be based on a delimiter of a sentence ending type (e.g. ".","!","?"). If you explain what you are trying to do or post some code more people will be willing to help.
If you are concerned about combined sentences (e.g. This is a single Sentence.Even though it is deliminated) you could expand upon this basic methodology. Special Characters seem to be much harder to handle. So positn what you are trying to do would be suggested
Sub sent_counter()
Dim s As Integer
For s = 1 To ActiveDocument.Sentences.Count
ActiveDocument.Sentences(s) = splitSentences(ActiveDocument.Sentences(s))
Next s
End Sub
Function splitSentences(s As String) As String
Dim delims As New Collection
Dim delim As Variant
delims.Add "."
delims.Add "!"
delims.Add "?"
Dim ender As String
Dim sub_s As String
s = Trim(s)
ender = Right(s, 1)
sub_s = Left(s, Len(s) - 1)
For Each delim In delims
If InStr(1, sub_s, delim) Then
sub_s = Replace(sub_s, delim, delim & " ")
End If
Next delim
splitSentences = sub_s & ender
End Function

GetCrossReferenceItems in msword and VBA showing only limited content

I want to make a special list of figures with use of VBA and here I am using the function
myFigures = ActiveDocument.GetCrossReferenceItems(Referencetype:="Figure")
In my word document there are 20 figures, but myFigures only contains the first 10 figures (see my code below.).
I search the internet and found that others had the same problem, but I have not found any solutions.
My word is 2003 version
Please help me ....
Sub List()
Dim i As Long
Dim LowerValFig, UpperValFig As Integer
Dim myTables, myFigures as Variant
If ActiveDocument.Bookmarks.Count >= 1 Then
myFigures = ActiveDocument.GetCrossReferenceItems(Referencetype:="Figure")
' Test size...
LowerValFig = LBound(myFigures) 'Get the lower boundry number.
UpperValFig = UBound(myFigures) 'Get the upper boundry number
' Do something ....
For i = LBound(myFigures) To UBound(myFigures) ‘ should be 1…20, but is onlu 1…10
'Do something ....
Next i
End If
MsgBox ("Done ....")
End Sub*
Definitely something flaky with that. If I run the following code on a document that contains 32 Figure captions, the message boxes both display 32. However, if I uncomment the For Next loop, they only display 12 and the iteration ceases after the 12th item.
Dim i As Long
Dim myFigures As Variant
myFigures = ActiveDocument.GetCrossReferenceItems("Figure")
MsgBox myFigures(UBound(myFigures))
MsgBox UBound(myFigures)
'For i = 1 To UBound(myFigures)
' MsgBox myFigures(i)
'Next i
I had the same problem with my custom cross-refference dialog and solved it by invoking the dialog after each command ActiveDocument.GetCrossReferenceItems(YourCaptionName).
So you type:
varRefItemsFigure1 = ActiveDocument.GetCrossReferenceItems(g_strCaptionLabelFigure1)
For k = 1 To UBound(varRefItemsFigure1)
frmBwtRefDialog.ListBoxFigures.AddItem varRefItemsFigure1(k)
Next
and then:
frmBwtRefDialog.Show vbModeless
Thus the dialog invoked several times instead of one, but it works fast and don't do any trouble. I used this for one year and didn't see any errors.
Enjoy!
Frankly I feel bad about calling this an "answer", but here's what I did in the same situation. It would appear that entering the debugger and stepping through the GetCrossReferenceItems always returns the correct value. Inspired by this I tried various ways of giving control back to Word (DoEvents; running next segment using Application.OnTime) but to no avail. Eventually the only thing I found that worked was to invoke the debugger between assignments, so I have:
availRefs =
ActiveDocument.GetCrossReferenceItems(wdRefTypeNumberedItem):Stop
availTables =
ActiveDocument.GetCrossReferenceItems(wdCaptionTable):Stop
availFigures = ActiveDocument.GetCrossReferenceItems(wdCaptionFigure)
It's not pretty but, as I'm the only person who'll be running this, it kind of works for my purposes.