PDA

View Full Version : [SOLVED:] Solved: Can you convert hard-entered endnotes to footnotes?



New Daddy
10-20-2012, 09:49 AM
Some academic databases convert footnotes to endnotes in a journal or article and place them at the end of the paper, in storing articles in text format. For example, in the body text, you would see "FN#" but the actual footnote will be found at the end of the document with the leading identifier "Footnote #" - practically an endnote. Needless to say, it really bogs you down to flip to the end of the document every time a footnote comes up and come back.

From the perspective of the database, it's the only way to preserve footnotes in an article, because there is no way to match the place of the footnote with the footnote text without pagination.

But from the reader's perspective, it's a PITA for the reader to navigate an article.

So, I was wondering if it is possible to automatically cut each paragraph starting with "Footnote #" and paste it where the corresponding "FN#" as the footnote. If this can be done, it will save a lot of reading time.

gmaxey
10-21-2012, 05:45 AM
You can do this with the built-in UI, but:

ActiveDocument.Endnotes.Convert

macropod
10-21-2012, 06:37 AM
Hi Greg,

That's works for footnotes that have been converted to true endnotes, but not for the kind of content one finds in PDFs etc.

For the specifications given, try:
Sub ReLinkFootNotes()
Dim i As Long, FtRng As Range, RngFt As Range
Dim StrFtRef As String, StrFtID As String
' Change the string represented by StrFtRef on the next line to
' whatever is appropriate for identifying the actual footnote content
StrFtRef = "Footnote "
' Change the string represented by StrFtID on the next line to whatever
' is appropriate for identifying the footnote references in the document
StrFtID = "FN"
Application.ScreenUpdating = False
With ActiveDocument
With .Content
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Forward = True
.Wrap = wdFindStop
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchAllWordForms = False
.MatchSoundsLike = False
.MatchWildcards = True
'Find the first qualifying footnote content
.Text = StrFtRef & "([0-9]{1,})"
.Replacement.Text = ""
.Execute
End With
If .Find.Found Then
Set FtRng = .Duplicate
Else
Beep
MsgBox "No applicable content found.", vbOKOnly
GoTo ErrExit
End If
'Find more qualifying footnote content
Do While .Find.Found
.Collapse wdCollapseEnd
.Find.Execute
Loop
FtRng.End = .Duplicate.Paragraphs.Last.Range.End - 1
DoEvents
'Eliminate the 'marker' text and ensure each footnote consists of one paragraph
With FtRng.Find
.MatchWildcards = True
.Wrap = wdFindStop
.Text = "[^11^13]{1,}"
.Replacement.Text = "^l"
.Execute Replace:=wdReplaceAll
.Text = StrFtRef & "([0-9]{1,})"
.Replacement.Text = "^p\1"
.Execute Replace:=wdReplaceAll
End With
FtRng.End = FtRng.End + 1
FtRng.Characters.First.Delete
DoEvents
For i = 1 To FtRng.Paragraphs.Count
StatusBar = "Locating Footnote Reference: " & i
With .Find
.Wrap = wdFindContinue
.Text = StrFtID & i
' Delete/comment out the next line if not applicable
.MatchWholeWord = True
.MatchWildcards = False
.Execute
End With
If .Find.Found = True Then
Set RngFt = .Duplicate
RngFt.Text = vbNullString
.Footnotes.Add Range:=RngFt, Text:=""
Set RngFt = FtRng.Paragraphs(i).Range
With RngFt
.End = .End - 2
.Start = .Words(2).Start
.Cut
End With
ActiveDocument.Footnotes(i).Range.Characters.Last.Previous.Paste
End If
DoEvents
Next i
FtRng.Text = vbNullString
End With
End With
ErrExit:
Set FtRng = Nothing: Set RngFt = Nothing
StatusBar = "Done!!"
Application.ScreenUpdating = True
End Sub
On my laptop it took less than a minute on a 28,000 word document, containing 10,000 words in 158 footnotes.

For the most part, formatting is retained. The only thing that isn't preserved is intra-footnote paragraph breaks & formatting - text formatting is retained, though.

gmaxey
10-21-2012, 08:09 AM
Paul,

Obviously, I did't understand the question. One problem I had with your code. The last character of the last footnote was cut off.

Test FN1
Test FN2
Test FN3

Footnote 1 A, A, A
Footnote 2 B, B, B
Footnote 3 C, C, C

resulted in:
1 A, A, A
2 B, B, B
3 C, C, C

If fixing it on my end I modifed your code a bit (just my preference):

Sub ReLinkFootNotesRevised()
Dim i As Long, FtRng As Range, RngFt As Range
Dim StrFtRef As String, StrFtID As String
Dim oTextRange As Word.Range 'Add GKM
' Change the string represented by StrFtRef on the next line to
' whatever is appropriate for identifying the actual footnote content
StrFtRef = "Footnote "
' Change the string represented by StrFtID on the next line to whatever
' is appropriate for identifying the footnote references in the document
StrFtID = "FN"
Application.ScreenUpdating = False
With ActiveDocument
With .Content
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Forward = True
.Wrap = wdFindStop
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchAllWordForms = False
.MatchSoundsLike = False
.MatchWildcards = True
'Find the first qualifying footnote content
.Text = StrFtRef & "([0-9]{1,})"
.Replacement.Text = ""
.Execute
End With
If .Find.Found Then
Set FtRng = .Duplicate
Else
Beep
MsgBox "No applicable content found.", vbOKOnly
GoTo ErrExit
End If
'Find more qualifying footnote content
Do While .Find.Found
.Collapse wdCollapseEnd
.Find.Execute
Loop
FtRng.End = .Duplicate.Paragraphs.Last.Range.End - 1
DoEvents
'Eliminate the 'marker' text and ensure each footnote consists of one paragraph
With FtRng.Find
.MatchWildcards = True
.Wrap = wdFindStop
.Text = "[^11^13]{1,}"
.Replacement.Text = "^l"
.Execute Replace:=wdReplaceAll
.Text = StrFtRef & "([0-9]{1,})"
.Replacement.Text = "^p\1"
.Execute Replace:=wdReplaceAll
'Eliminate any doubled up line and paragrahs. 'Added GKM
.Text = "^11^13"
.Replacement.Text = "^p"
.Execute Replace:=wdReplaceAll
End With
FtRng.End = FtRng.End + 1
FtRng.Select
FtRng.Characters.First.Delete
DoEvents
FtRng.Select
For i = FtRng.Paragraphs.Count To 1 Step -1
StatusBar = "Locating Footnote Reference: " & i
With .Find
.Wrap = wdFindContinue
.Text = StrFtID & i
' Delete/comment out the next line if not applicable
.MatchWholeWord = True
.MatchWildcards = False
.Execute
End With
If .Find.Found = True Then
Set RngFt = .Duplicate
Set oTextRange = FtRng.Paragraphs(i).Range.Duplicate
oTextRange.MoveStart wdWord, 1
oTextRange.End = oTextRange.End - 1
RngFt.Text = vbNullString
.Footnotes.Add Range:=RngFt, Text:=oTextRange.Text
FtRng.Paragraphs(i).Range.Delete
End If
DoEvents
Next i
FtRng.Text = vbNullString
End With
End With
ErrExit:
While Len(ActiveDocument.Paragraphs.Last.Range) = 1 'Added GKM
ActiveDocument.Paragraphs.Last.Range.Delete
Wend
Set FtRng = Nothing: Set RngFt = Nothing
StatusBar = "Done!!"
Application.ScreenUpdating = True
End Sub

macropod
10-21-2012, 01:32 PM
Thanks for spotting that Greg.

With my code, the fix is as simple as cchanging:
FtRng.End = .Duplicate.Paragraphs.Last.Range.End - 1
to:
FtRng.End = .Duplicate.Paragraphs.Last.Range.End
(the - 1 was a legacy of a different approach I tried).

PS: The limitation with your approach is that text formatting within the source 'footnotes' is lost.

macropod
10-21-2012, 02:51 PM
Cross-posted at: http://www.msofficeforums.com/word-vba/14798-converting-hard-entered-endnotes-footnotes.html
For cross-posting etiquette, please read: http://www.excelguru.ca/content.php?184

New Daddy
10-21-2012, 07:06 PM
Hi Greg,

That's works for footnotes that have been converted to true endnotes, but not for the kind of content one finds in PDFs etc.

For the specifications given, try:
VBA:

On my laptop it took less than a minute on a 28,000 word document, containing 10,000 words in 158 footnotes.

For the most part, formatting is retained. The only thing that isn't preserved is intra-footnote paragraph breaks & formatting - text formatting is retained, though.

This is superb! Thanks so much. I tried to write one on my own, but was stuck at where I had to match the footnote text at the end of the text to the foot note number.

By the way, this macro generated an error when a footnote contained a table.

macropod
10-21-2012, 09:22 PM
Your footnotes contain tables??!! That's not something I'd have expected.

As indicated in my initial post, the code is designed to convert each footnote to a single paragraph. That can't be done when there's a table in the mix.

The reason you'll get a run-time error with tables is that, when the macro tries to loop through the footnote range, it finds a 'paragraph' without the expected footnote number.

fumei
10-21-2012, 11:39 PM
Footnotes containing tables? That is quite unusual.

gmaxey
10-22-2012, 03:16 AM
Paul,

Got it. Like with the surprise table, that is the problem with me using over simplified test documents. They don't adequately define the scope of work.

Thanks.


Thanks for spotting that Greg.

With my code, the fix is as simple as cchanging:
FtRng.End = .Duplicate.Paragraphs.Last.Range.End - 1
to:
FtRng.End = .Duplicate.Paragraphs.Last.Range.End
(the - 1 was a legacy of a different approach I tried).

PS: The limitation with your approach is that text formatting within the source 'footnotes' is lost.

macropod
10-22-2012, 03:57 AM
that is the problem with me using over simplified test documents. They don't adequately define the scope of work.
I've been caught all too often with that one too. And, I'm sure we've both been caught by 'clients' who inadequately specified their requirements (not that I'm saying that applies in this thread).

gmaxey
10-22-2012, 05:12 AM
Paul,

I've got to go to regular work, but tried to finish this before I left. I think, by using a temporary document, the table requirement can be met:

Sub ConvertHardEndNotesToDynamicFootnotes()
Dim oDoc As Word.Document
Dim oDocTemp As Word.Document
Dim lngIndex As Long
Dim oRngFNRef As Range, oRngFNs As Range
Dim arrFNs() As Long
Dim arrID() As String
Dim strFNRef As String, strFN_ID As String

'Get variable values from user.
strFNRef = InputBox("Enter the text string that identifies\enumerates each end\footnote in the end\footnote text. " & vbCr _
& "Be sure to include the trailing space and use ""#"" to represent the number. (e.g., ""Footnote # - "").", "Enumerator Text", "Footnote #: ")

arrID() = Split(strFNRef, " ")

strFN_ID = InputBox("Enter the text string that identifies\enumerates each end\footnote in the document text. " & vbCr _
& "Be sure to include any leading space and use ""#"" to represent the number. (e.g., "" FN#"").", "Enumerator Text", " FN#")

Application.ScreenUpdating = False
Set oDoc = ActiveDocument

'Reset all find and replace parameters to the default value.
ResetFRParameters
'Identify the the text of the endnote section of the document.
'This is all text from the first enumerated endnote, to the end of the document text.
With oDoc.Content
With .Find
'Find the first qualifying hard endnote.
.Text = Replace(strFNRef, "#", "([0-9]{1,})")
.MatchWildcards = True
.Execute
End With
If .Find.Found Then
Set oRngFNs = .Duplicate
Else
Beep
MsgBox "No applicable content found.", vbOKOnly
GoTo lbl_Exit
End If
oRngFNs.End = oDoc.Paragraphs.Last.Range.End
DoEvents

'Cut and paste this text to a temporary document.
oRngFNs.Cut
Set oDocTemp = Documents.Add
oDocTemp.Range.Paste

'Identify and store the range .start value of each hard endnote.
Set oRngFNs = oDocTemp.Range
With oRngFNs.Find
.MatchWildcards = True
.Text = Replace(strFNRef, "#", "([0-9]{1,})")
While .Execute
If .Found Then
ReDim Preserve arrFNs(lngIndex)
arrFNs(lngIndex) = oRngFNs.Start
lngIndex = lngIndex + 1
End If
Wend
ReDim Preserve arrFNs(lngIndex)
arrFNs(lngIndex) = oDocTemp.Paragraphs.Last.Range.End
End With

DoEvents

'Create the footnotes in the document.
For lngIndex = 0 To UBound(arrFNs) - 1
StatusBar = "Locating Footnote Reference: " & lngIndex

'Find the reference.
With .Find
.Text = Replace(strFN_ID, "#", "") & lngIndex + 1
'Delete/comment out the next line if not applicable
.Wrap = wdFindContinue
.MatchWholeWord = True
.MatchWildcards = False
.Execute
End With
If .Find.Found = True Then
Set oRngFNRef = .Duplicate
'Wipe the existing reference and create empty dynamic footnote.
oRngFNRef.Text = vbNullString
.Footnotes.Add Range:=oRngFNRef, Text:=""

'Get the footnote text from the temporary document.
Set oRgnFNs = oDocTemp.Range
With oRgnFNs
.Start = arrFNs(lngIndex)
.End = arrFNs(lngIndex + 1) - 1
.Start = .Words(UBound(arrID) + 1).Start
.Copy
End With

'Put it it in the dynamic footnote.
oDoc.Activate
oDoc.Footnotes(lngIndex + 1).Range.Characters.Last.Previous.Select
oDoc.Footnotes(lngIndex + 1).Range.Characters.Last.Previous.Paste
'oDoc.Footnotes(lngIndex + 1).Range.Style = "Footnote Text"
End If
DoEvents
Next lngIndex
End With
lbl_Exit:
oDocTemp.Close wdDoNotSaveChanges
Set oRngFNRef = Nothing: Set oRngFNs = Nothing
StatusBar = "Done!!"
Application.ScreenUpdating = True
End Sub
Sub ResetFRParameters()
With Selection.Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = ""
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindStop 'Continue
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
.Execute
End With
End Sub



What say ye?

New Daddy
10-22-2012, 09:50 AM
What say ye?

It solved the table-in-footnote problem, but resulted in another problem that didn't happen previously. At the end of the footnotes-in-the-form-of-endnotes in the original document was a section break. That section break is causing an error in this macro, which didn't happen in your previous macro. Of course, knowing this, I can get rid of the breaks manually before running this macro, which otherwise is excellent! I especially like the extra step where you ask the end-user about the format of the footnotes, as they vary from one document to another.

Two more nit-picky comments: there are a couple of typos in the macro - all misspells of oRngFNs and occasionally the last footnote of a page is pushed down to the next page even when there is sufficient space for footnotes on the proper page.

macropod
10-22-2012, 03:55 PM
What you're running up against is the limits of what can be done with coding to try to define a processing range via code. The only reason my code didn't fail with the Section break was that it assumed, rightly or wrongly, that the last 'footnote' consisted of a single paragraph. On the basis of your specifications:

the actual footnote will be found at the end of the document
I could have just as easily assumed that it terminated at the end of the document, in which case my code too would have fallen foul of the unspecified Section break(s).

FWIW, if I were to have modified my code to handle multi-para footnotes, I'd have done it all without creating a temporary document, but that seems rather moot now.

New Daddy
10-22-2012, 04:41 PM
What you're running up against is the limits of what can be done with coding to try to define a processing range via code. The only reason my code didn't fail with the Section break was that it assumed, rightly or wrongly, that the last 'footnote' consisted of a single paragraph. On the basis of your specifications:

I could have just as easily assumed that it terminated at the end of the document, in which case my code too would have fallen foul of the unspecified Section break(s).

FWIW, if I were to have modified my code to handle multi-para footnotes, I'd have done it all without creating a temporary document, but that seems rather moot now.

I have no issue with that. Overall, it's an excellent piece of programming and really shows what VBA can do that otherwise cannot conceivably done.

Thanks!

New Daddy
12-05-2012, 02:06 PM
Hi Greg,

That's works for footnotes that have been converted to true endnotes, but not for the kind of content one finds in PDFs etc.

For the specifications given, try:


The macro has served me well over the months. But a new situation occurred. There is a chapter from a treatise that contains footnotes with decimals. (e.g., FN 24.1, FN 24.2, etc.) It turns out that decimal footnotes are not unusual in treatises, because authors want their work to maintain continuity over different editions to the extent possible.

I ran the macro on a document with decimal footnotes, and the result was not right. I took a look at the temporary document, and it looks like the macro was able to detect all the endnotes with decimal numbers and moved them to the temporary document. I think it's during matching those endnotes with the footnote numbers (with decimals) in the main text that created the error.

I tried to revise the code, but it's obviously beyond me. Any fix for this?

macropod
12-05-2012, 06:55 PM
While you've been away, Greg and I have been playing: http://gregmaxey.mvps.org/word_tip_pages/convert_reference_notes_to_dynamic_footnotes.html
With the new code there, I think you should be able to input 'FN 24.#' as the criterion.

New Daddy
12-10-2012, 01:50 PM
While you've been away, Greg and I have been playing: http://gregmaxey.mvps.org/word_tip_pages/convert_reference_notes_to_dynamic_footnotes.html
With the new code there, I think you should be able to input 'FN 24.#' as the criterion.

After correcting one typo (lngCounter => lngCount), I ran it on the document with decimal footnotes, but it keeps saying "No fixed endnote (or footnote) found."

I went back to the macro in this thread and tried as you suggested (i.e., FN 24.#). The macro is able to move Footnotes 24.1 through 24.# to the appropriate place in the body. However, it also moved the remaining footnotes (Footnotes 25 and beyond) to the last 24.# footnote. This behavior is understandable, since the macro couldn't tell whether "Footnote 25" was part of "Footnote 24.xx" or the beginning of a new footnote. To make a long story short, I moved all the fixed footnotes at the end of the document following 24.# to a separate document, ran the macro, copied the footnotes back to the document, and ran the macro again. This is very laborious (because there are multiple instances of footnotes with decimals) but does the job.

But there is a bigger hurdle that I hadn't realized: Word doesn't know decimal footnotes. It numbers the footnotes in integer numbers. This would be fine unless the text or footnotes don't refer to a footnote. Unfortunately, treatises often refer to footnotes, so all bets are off.

Authors should stop using footnotes with decimals.

macropod
12-10-2012, 02:57 PM
Word does not provide support for a decimal footnote numbering system.

The only way you'll be able to restore such a system is to have section-based footnote numbering and to re-insert the integer portion of the decimal numbers (plus their periods) before the footnote references in both the body and in the footnotes.

New Daddy
01-19-2014, 03:12 PM
Paul,

I've got to go to regular work, but tried to finish this before I left. I think, by using a temporary document, the table requirement can be met:

Sub ConvertHardEndNotesToDynamicFootnotes()
Dim oDoc As Word.Document
Dim oDocTemp As Word.Document
Dim lngIndex As Long
Dim oRngFNRef As Range, oRngFNs As Range
Dim arrFNs() As Long
Dim arrID() As String
Dim strFNRef As String, strFN_ID As String

'Get variable values from user.
strFNRef = InputBox("Enter the text string that identifies\enumerates each end\footnote in the end\footnote text. " & vbCr _
& "Be sure to include the trailing space and use ""#"" to represent the number. (e.g., ""Footnote # - "").", "Enumerator Text", "Footnote #: ")

arrID() = Split(strFNRef, " ")

strFN_ID = InputBox("Enter the text string that identifies\enumerates each end\footnote in the document text. " & vbCr _
& "Be sure to include any leading space and use ""#"" to represent the number. (e.g., "" FN#"").", "Enumerator Text", " FN#")

Application.ScreenUpdating = False
Set oDoc = ActiveDocument

'Reset all find and replace parameters to the default value.
ResetFRParameters
'Identify the the text of the endnote section of the document.
'This is all text from the first enumerated endnote, to the end of the document text.
With oDoc.Content
With .Find
'Find the first qualifying hard endnote.
.Text = Replace(strFNRef, "#", "([0-9]{1,})")
.MatchWildcards = True
.Execute
End With
If .Find.Found Then
Set oRngFNs = .Duplicate
Else
Beep
MsgBox "No applicable content found.", vbOKOnly
GoTo lbl_Exit
End If
oRngFNs.End = oDoc.Paragraphs.Last.Range.End
DoEvents

'Cut and paste this text to a temporary document.
oRngFNs.Cut
Set oDocTemp = Documents.Add
oDocTemp.Range.Paste

'Identify and store the range .start value of each hard endnote.
Set oRngFNs = oDocTemp.Range
With oRngFNs.Find
.MatchWildcards = True
.Text = Replace(strFNRef, "#", "([0-9]{1,})")
While .Execute
If .Found Then
ReDim Preserve arrFNs(lngIndex)
arrFNs(lngIndex) = oRngFNs.Start
lngIndex = lngIndex + 1
End If
Wend
ReDim Preserve arrFNs(lngIndex)
arrFNs(lngIndex) = oDocTemp.Paragraphs.Last.Range.End
End With

DoEvents

'Create the footnotes in the document.
For lngIndex = 0 To UBound(arrFNs) - 1
StatusBar = "Locating Footnote Reference: " & lngIndex

'Find the reference.
With .Find
.Text = Replace(strFN_ID, "#", "") & lngIndex + 1
'Delete/comment out the next line if not applicable
.Wrap = wdFindContinue
.MatchWholeWord = True
.MatchWildcards = False
.Execute
End With
If .Find.Found = True Then
Set oRngFNRef = .Duplicate
'Wipe the existing reference and create empty dynamic footnote.
oRngFNRef.Text = vbNullString
.Footnotes.Add Range:=oRngFNRef, Text:=""

'Get the footnote text from the temporary document.
Set oRgnFNs = oDocTemp.Range
With oRgnFNs
.Start = arrFNs(lngIndex)
.End = arrFNs(lngIndex + 1) - 1
.Start = .Words(UBound(arrID) + 1).Start
.Copy
End With

'Put it it in the dynamic footnote.
oDoc.Activate
oDoc.Footnotes(lngIndex + 1).Range.Characters.Last.Previous.Select
oDoc.Footnotes(lngIndex + 1).Range.Characters.Last.Previous.Paste
'oDoc.Footnotes(lngIndex + 1).Range.Style = "Footnote Text"
End If
DoEvents
Next lngIndex
End With
lbl_Exit:
oDocTemp.Close wdDoNotSaveChanges
Set oRngFNRef = Nothing: Set oRngFNs = Nothing
StatusBar = "Done!!"
Application.ScreenUpdating = True
End Sub
Sub ResetFRParameters()
With Selection.Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = ""
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindStop 'Continue
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
.Execute
End With
End Sub



What say ye?

I have a minor quibble. The macro above does its job well, but leaves no space between the dynamic footnote number and the corresponding footnote text. I've tried to modify the macro to make it do so, but failed. Could you show me how to do it? Thanks.

macropod
01-20-2014, 01:10 AM
Is there a reason you're not using the code in the link you were provided in post #17? Are you sure your 'hard notes' include the required space?

New Daddy
01-20-2014, 10:51 AM
Is there a reason you're not using the code in the link you were provided in post #17? Are you sure your 'hard notes' include the required space?

Well, for some strange reason, the macro provided in post #17 doesn't work, while the one provided in post #12 works fine. I get "No Fixed Note Content Found" with the macro in post #17 using the same text strings as with post #12.