PDA

View Full Version : Solved: Moving punctuation – endnotes and cross references



BoatwrenchV8
05-23-2012, 12:25 PM
I have another 80 page document with Word endnotes andcross references, 539 total fields and the last endnote is #112. The punctuation is in the wrong place relative to the endnotes and cross references in nearly all instances. It is in the format of punctuation then field (so the field is outside of the punctuation). It needs to be reversed so it is field then punctuation (then the field is inside of the punctuation).

Please see attached file for a sample.

The plan I had will not work, to start at the top and go towards the bottom, looking forfields. When a field is found, then lookup for punctuation. When found, switch the punctuation if it is next to the field. That will not work because there are many endnotes and cross references scattered in the document that are made up of multiple items separated with a comma in the middle and at the end of sentences. This is not a situation I can do my usual, record a macro and then modify it. I am using Word 2010 and am looking for suggestions.

macropod
05-25-2012, 02:17 AM
I have another 80 page document with Word endnotes andcross references, 539 total fields and the last endnote is #112. The punctuation is in the wrong place relative to the endnotes and cross references in nearly all instances. It is in the format of punctuation then field (so the field is outside of the punctuation).
AFAIK, that's how they are supposed to be. Indeed, I've previously posted a macro to help someone ensure that's how all their footnote and endnote references appear in a document!! And here 'tis:
Sub FootnoteEndnoteFix()
Dim FtNt As Footnote, EndNt As Endnote
With ActiveDocument
For Each FtNt In .Footnotes
With FtNt.Reference
Select Case .Characters.Last.Next
Case ".", ",", "!", "?", ";"
.InsertBefore .Characters.Last.Next
.Characters.Last.Next.Delete
End Select
End With
Next
For Each EndNt In .Endnotes
With EndNt.Reference
Select Case .Characters.Last.Next
Case ".", ",", "!", "?", ";"
.InsertBefore .Characters.Last.Next
.Characters.Last.Next.Delete
End Select
End With
Next
End With
End Sub
It requires only minor tweaking to do the opposite... With a bit more work, it could be extended to PAGEREF fields, etc, too.

BoatwrenchV8
05-28-2012, 06:03 PM
Thank you Macropod. Will experiment with this and will repost ASAP.

BoatwrenchV8
05-29-2012, 05:45 PM
Macropod, I have modified your code and have gotten it to work but have another problem. There are a lot of cross references and endnotes separated with commas. When the macro finds a clump of cross references and endnotes separated by commas, it removes the last superscripted comma and places it at the end. How do I have it omit the puctuation that is superscripted? Please see the sample I attached to the original post showing the way the document is now versus how it is supposed to look. Thank you for all your help.

Sub FootnoteEndnoteFix()
Dim EndNt As Endnote
Dim PunctuationCharacter As Variant

With ActiveDocument
'
For Each EndNt In .Endnotes
With EndNt.Reference
MsgBox EndNt.Reference.Characters.First.Previous
PunctuationCharacter = EndNt.Reference.Characters.First.Previous
Select Case .Characters.First.Previous

Case ".", ",", "!", "?", ";"

.Characters.First.Previous.Delete
.InsertAfter PunctuationCharacter
End Select
End With
Next
End With
End Sub

BoatwrenchV8
05-29-2012, 06:00 PM
Picture of the attached sample file is attached after the macro was ran. First paragraph (with the "wrong" formatting) shows the problem with the comma being moved. I need superscripted commas to be excluded, but all other commas to be included. Second paragraph has formattiing that is considered to be correct.

Frosty
05-30-2012, 11:04 AM
Boatwrench,

It's a good habit to step through code so you can see what's happening, rather than do the messagebox to force yourself to stop. Try using breakpoints (F9) and stepping through (F8) and watch as the document changes. I think you'd find that, in this case, your description of the problem isn't totally accurate.

Also, always better not to rely on Variant unless you have to. Characters are a range. That would give you hints toward what your options are. Here is slightly modified version of your code-- I think this is what you want.

Sub FootnoteEndnoteFix()
Dim EndNt As Endnote
Dim PunctuationCharacter As Range

With ActiveDocument
For Each EndNt In .Endnotes
With EndNt.Reference
Set PunctuationCharacter = .Characters.First.Previous
MsgBox PunctuationCharacter.Text
Select Case PunctuationCharacter

Case ".", ",", "!", "?", ";"
If PunctuationCharacter.Font.Superscript = False Then
.Characters.First.Previous.Delete
.InsertAfter PunctuationCharacter.Text
End If
End Select
End With
Next
End With
End Sub
Also-- comment comment comment. Always comment your code. That helps in so many ways -- not only does it help other people learn what you want to do (rather than what you're doing), it also serves to help you organize your own thoughts about how to proceed. I have often solved my own problems simply by commenting and realizing there was a better approach.

BoatwrenchV8
05-30-2012, 01:04 PM
Thank you for your code Frosty. I am still experimenting with this. Two problems have come up. One is when there are 2 endnotes separated with a superscriped comma but in a sentence with a regular comma. For example: "The quick brown,[superscripted endnote][superscripted comma][superscripted endnote] jumped over..." turns into after I ran your code, "The quick brown[superscripted endnote][comma][superscripted comma][superscripted endnote] jumped over..."

I am trying to fix that by looking at the pervious punctuation and if it not superscripted, put it at the end of the endnote.

The second problem is there are endnotes and cross references mixed together. I should be able to use the same base code, but instead of looking for endnote objects, look for and modify field objects, right?

I have made a few changes to your code and inserted some comments. Ranges are a bit new to me, I have been doing most of what I do using selection. I have stepped thru the code but used the message box so I could see what range the code was accessing. I commented the message box out and just put a .select to select it.

Is everything in the with block and the if then block referring to EndNt.Reference?



Sub FootnoteEndnoteFix()
Dim EndNt As Endnote
Dim PunctuationCharacter As Range
Dim PreviousPunctuationCharacter As Range

With ActiveDocument
For Each EndNt In .Endnotes 'For each EndNt object in endnotes collection
With EndNt.Reference 'Get endnote object reference number
.Select 'Select the endnote to help ID what is going on.

Set PunctuationCharacter = .Characters.First.Previous
Set PreviousPunctuationCharacter = PunctuationCharacter.Characters.First.Previous

' MsgBox PunctuationCharacter.Text

Select Case PunctuationCharacter
Case ".", ",", "!", "?", ";", " " 'if punctuations in this list, enter block

If PunctuationCharacter.Font.Superscript = False Then
'.Characters.First.Previous.Delete
.InsertAfter PunctuationCharacter.Text 'insert punctuation after endnote
.Characters.First.Previous.Delete 'Del previous range first char.

End If
End Select

'if [SS Endnote][regularpunctuation][SS punctuation][SS Endnote],
' put regular punctuation the end of the range
'
'****** THIS PART IS NOT WORKING CORRECTLY
'

Select Case PreviousPunctuationCharacter
Case ".", ",", "!", "?", ";", " " 'if in this list, enter block
If PreviousPunctuationCharacter.Font.Superscript = False Then

EndNt.Reference.InsertAfter PreviousPunctuationCharacter.Text
.Characters.First.Previous.Delete 'Del previous range first char.
End If
End Select
End With
Next
End With
End Sub

BoatwrenchV8
05-30-2012, 01:45 PM
I got it to work, now I have to get the cross references fixed as well. Looks like my idea to basically use the same code to fix the cross references will not work. Suggestions?

Sub FootnoteEndnoteFix()
Dim EndNt As Endnote

Dim PunctuationCharacter As Range
Dim PreviousPunctuationCharacter As Range

With ActiveDocument
For Each EndNt In .Endnotes 'For each EndNt object in endnotes collection
With EndNt.Reference 'Get endnote object reference number
.Select 'Select the endnote to help ID what is going on.

Set PunctuationCharacter = .Characters.First.Previous
Set PreviousPunctuationCharacter = PunctuationCharacter.Characters.First.Previous

' MsgBox PunctuationCharacter.Text

Select Case PunctuationCharacter
Case ".", ",", "!", "?", ";", " " 'if punctuations in this list, enter block

If PunctuationCharacter.Font.Superscript = False Then
'.Characters.First.Previous.Delete
.InsertAfter PunctuationCharacter.Text 'insert punctuation after endnote
.Characters.First.Previous.Delete 'Del previous range first char.

End If
End Select

'if [SS Endnote][regularpunctuation][SS punctuation][SS Endnote],

Select Case PreviousPunctuationCharacter
Case ".", ",", "!", "?", ";", " " 'if in this list, enter block
If PreviousPunctuationCharacter.Font.Superscript = False Then

.InsertAfter PreviousPunctuationCharacter.Text
.Characters.Last.Font.Superscript = False
' PreviousPunctuationCharacter.Font.Superscript = False
PreviousPunctuationCharacter.Delete 'Del previous range first char.
End If
End Select
End With
Next
End With

Frosty
05-30-2012, 02:18 PM
This is a different essential structure... but there are two main points to this.

1. Learning to work with ranges allows you to separate how you deal with individual objects
2. You want to loop through two sets of ranges-- all the ranges of each endnote's reference-- and then ranges of each xref, but you want to handle both of them in the same way.

The following code does *not* handle your "...Home tab. [1],[2],[3],[9]" scenario, because you have your xref preceeded by a space, rather than a period. I leave that solution to you... see if this helps though.

'Format all endnote and xref such that any punctuation not superscripted
'comes immediately after the endnote/xref rather than before it
Sub FixEndnotesAndXRefs()
Dim oEndNt As Endnote
Dim oFtNT As Footnote
Dim oField As Field

For Each oEndNt In ActiveDocument.Endnotes
fHandleRange oEndNt.Reference.Duplicate
Next

For Each oField In ActiveDocument.Fields
If oField.Type = wdFieldNoteRef Then
fHandleRange oField.Result.Duplicate
End If
Next
End Sub
'pass in the range, and punctuate properly
Sub fHandleRange(rngOrig As Range)
Dim sPunctuation As String
Dim rngWorking As Range
Dim rngWhere As Range

Set rngWhere = rngOrig.Characters.First.Previous
sPunctuation = rngWhere.Text
Select Case sPunctuation
'if the very next character is punctuation
Case ".", ",", "!", "?", ";"
'make sure it's not superscripted, before we do anything with it
If rngWhere.Font.Superscript = False Then
'okay to delete it
rngWhere.Delete
'and since we've deleted it, then we need to put it somewhere
'start looking for the right spot...
Set rngWorking = rngOrig.Characters.Last.Next
'move the range until we have a spot to insert
Do Until rngWorking Is Nothing
If rngWorking.Font.Superscript = True Then
rngWorking.Move wdCharacter, 1

Else
rngWorking.InsertBefore sPunctuation
rngWorking.Font.Superscript = False
Exit Do
End If
Loop

End If
'Stop
Case Else
'it's good practice to always have a case else, even if not used
End Select

End Sub
Sorry to give you the whole answer in a different way that you were dealing with it (particularly with regards to the Do...Loop structure), but it was easier for me to give you this than to explain all the things I didn't like about what you were doing.
I would tend to avoid dealing with nested With...End With code structures until you understand how that structure works a bit. In addition to readability issues (trying to remember where what section you're in), there are other ramifications when you are modifying ranges within With...End With blocks of those actual ranges.

Frosty
05-30-2012, 02:27 PM
Actually, I discovered one bug in this process, in that deleting the range doesn't seem to work in a certain scenario. I've also added something that only works in Word 2010 (and maybe 2007)... consolidating all the actions into a single custom undo. Try this...

Sub FixEndnotesAndXRefs()
Dim oEndNt As Endnote
Dim oFtNT As Footnote
Dim oField As Field

Application.UndoRecord.StartCustomRecord "FixEndnotesAndXrefs"
For Each oEndNt In ActiveDocument.Endnotes
fHandleRange oEndNt.Reference.Duplicate
Next

For Each oField In ActiveDocument.Fields
If oField.Type = wdFieldNoteRef Then
fHandleRange oField.Result.Duplicate
End If
Next
Application.UndoRecord.EndCustomRecord
End Sub
'pass in the range, and punctuate properly
Sub fHandleRange(rngOrig As Range)
Dim sPunctuation As String
Dim rngWorking As Range
Dim rngWhere As Range

Set rngWhere = rngOrig.Characters.First.Previous
sPunctuation = rngWhere.Text
Select Case sPunctuation
'if the very next character is punctuation
Case ".", ",", "!", "?", ";"
'make sure it's not superscripted, before we do anything with it
If rngWhere.Font.Superscript = False Then
'okay to delete it
'rngWhere.Delete
rngWhere.Text = ""
'and since we've deleted it, then we need to put it somewhere
'start looking for the right spot...
Set rngWorking = rngOrig.Characters.Last.Next
'move the range until we have a spot to insert
Do Until rngWorking Is Nothing
If rngWorking.Font.Superscript = True Then
rngWorking.Move wdCharacter, 1

Else
rngWorking.InsertBefore sPunctuation
rngWorking.Font.Superscript = False
Exit Do
End If
Loop

End If
'Stop
Case Else
'it's good practice to always have a case else, even if not used
End Select

End Sub

Take out the application.undorecord lines if you get compile errors.

BoatwrenchV8
05-30-2012, 02:45 PM
Perfect!! Works just like I needed. Thank you very much Frosty. :bow:

I have to make sure there aren't any preceeding spaces before the endnotes or cross references but I can do that using Find and Replace.

Now that I can get the immediate fire out, I can study your code so I can figure out exactly what is going on.

Frosty
05-30-2012, 02:50 PM
The best way to approach is to step through the code... and utilize the immediate window. At various points, you should use
rngOrig.Select
rngWhere.Select
rngWorking.Select
?sPunctuation

The last one you can also achieve by either hovering over the variable in the code window, or utilizing the Locals Window.

Usage of the above techniques will really really help you in breaking apart code to see what it's doing. The next thing is to use the Watches window, but leave that for a little later when you get more familiar with the above techniques.

Good luck!

BoatwrenchV8
05-30-2012, 03:01 PM
The other problem I have had has been clearly seeing how the various objects, methods, properties and so on fit together with eachother. The VBA help is not too swift and the object browser is not a real help. Neither really show the big picture. I am still looking for a chart I can put on the wall. Not find one yet. Looks like I will have to make one.

I will mark this as solved after I run the macro on the actual document.

Thank you again Frosty.

Frosty
05-30-2012, 03:05 PM
The Object Browser is extremely useful... but it's also extremely intimidating. Apart from having a good teacher, I think the best way to learn is a combination of forums like these, recording macros, and using the help file on any objects you're not familiar with. From there, you can see what properties and methods are available for that object.

But learning the ins and outs of working with ranges will give you two things: 1) familiarity with one of the more useful objects to know in Word 2) familiarity with the *process* of learning about any object.

I don't have the entire Word object model floating around in my head. And if I did have a diagram on the wall as you suggest, it would be vast. Or such a small font as to be unreadable. In any event, the other place to learn is to use the Locals window and the Watch Window. This gives you a dynamic ability to see what objects you're currently using, as well as a tree view of the available properties and objects. You don't learn about the methods available (help and recorded macros give you that info), but it's a start.

BoatwrenchV8
06-04-2012, 09:32 PM
Thank you Frosty and Macropod for your help with this.

Rich

macropod
08-12-2012, 04:35 PM
Hi Rich,

I've had occasion to re-visit this. Try the following - it should delete any preceding spaces as well.
Sub FootnoteEndnoteFix()
Dim FtNt As Footnote, EndNt As Endnote, Rng As Range
With ActiveDocument
For Each FtNt In .Footnotes
Set Rng = FtNt.Reference.Characters.First
With Rng
While .Characters.First.Previous.Text = " "
.Characters.First.Previous.Text = vbNullString
Wend
While .Characters.Last.Next.Font.Superscript = True
.End = .End + 1
Wend
Select Case .Characters.First.Previous
Case ".", ",", "!", "?", ";"
.InsertAfter .Characters.First.Previous
.Characters.First.Previous.Text = vbNullString
.Characters.Last.Font.Superscript = False
End Select

End With
Next
For Each EndNt In .Endnotes
Set Rng = EndNt.Reference.Characters.First
With Rng
While .Characters.First.Previous.Text = " "
.Characters.First.Previous.Text = vbNullString
Wend
While .Characters.Last.Next.Font.Superscript = True
.End = .End + 1
Wend
Select Case .Characters.First.Previous
Case ".", ",", "!", "?", ";"
.InsertAfter .Characters.First.Previous
.Characters.First.Previous.Text = vbNullString
.Characters.Last.Font.Superscript = False
End Select

End With
Next
End With
End Sub

BoatwrenchV8
08-15-2012, 11:31 AM
Thank you for your reply to this Paul. I tried your code on a sample document I created for a different, but still endnote and cross reference related issue (http://www.msofficeforums.com/word/13140-pasting-endnotes-x-refs-into-another-document.html), and it did not work as hoped. Any commas between endnotes or endnotes and cross references were moved to the end and not superscripted. I will look into this further and post back again as soon as I can. Very soon, I forsee another document coming my way with a jumbled up mess of punctuation, spaces mixed into the cross references and endnotes.

macropod
08-15-2012, 06:48 PM
Thank you for your reply to this Paul. I tried your code on a sample document I created ... and it did not work as hoped. Any commas between endnotes or endnotes and cross references were moved to the end and not superscripted.
The only character the macro operates on is the one before the series, which essentially gets moved to the end. The intervening ones are left alone.

PS: I did modify the code a bit a few minutes after posting, so you might do better with the code that's now in the post.

BoatwrenchV8
08-23-2012, 03:50 PM
Paul,
Yes! It works well and cleans up endnotes. I will be using this for certain pretty soon. Thank you very much for your help with this. :)
Rich