Deleting all hyperlinks

M

mrgou

Hi,

I want to delete all hyperlinks from my document, but the following
macro doesn't work

Sub DeleteLinks()
Dim MyHLink As Hyperlink
For Each MyHLink In ActiveDocument.Hyperlinks
MyHLink.Delete
Next MyHLink
End Sub

Any idea why?

Thanks!

Raph
 
P

Pesach Shelnitz

Hi Raph,

In general, to delete all the objects from a collection in VBA, you need a
For loop that iterates through the collection in descending order. The first
of the following macros converts all the hyperlinks in the active document to
ordinary text, and the second macro completely erases all the hyperlinks.

Sub ConvertHyperlinksToText()
Dim i As Long

With ActiveDocument
For i = .Hyperlinks.Count To 1 Step -1
.Hyperlinks(i).Delete
Next
End With
End Sub

Sub DeleteHyperlinks()
Dim i As Long

With ActiveDocument
For i = .Hyperlinks.Count To 1 Step -1
.Hyperlinks(i).Range.Delete
Next
End With
End Sub
 
M

mrgou

In general, to delete all the objects from a collection in VBA, you need a
For loop that iterates through the collection in descending order. The first
of the following macros converts all the hyperlinks in the active document to
ordinary text, and the second macro completely erases all the hyperlinks. [snip]
Hope this helps,

Indeed it does, although I don't understand how your second macro is
different from mine in the end. I thought a For Each loop in a
collection would iterate through all objects of that collection. Your
goes backwards, but why does it make a difference?

Many thanks for your help!

Raph
 
G

Greg Maxey

Sub FindAndItalicBoundText()
Dim oRng As Range
Set oRng = ActiveDocument.Content
With oRng.Find
.ClearFormatting
.Text = "^^<*>^^"
.Forward = True
.Wrap = wdFindStop
.MatchWildcards = True
Do While .Execute
With oRng
.Characters.First.Delete
.Characters.Last.Delete
.Font.Italic = True
.Collapse wdCollapseEnd
End With
Loop
End With
End Sub
 
G

Greg Maxey

<I thought a For Each loop in a collection would iterate through all objects
of that collection ...

It does. For example if you were changing the font color or your hyperlinks
then a basic for each loop like you wrote would be sufficient.

Sub ChangeColor()
Dim MyHLink As Hyperlink
For Each MyHLink In ActiveDocument.Hyperlinks
MyHLink.Range.Font.Color = wdColorRed
Next MyHLink
End Sub

The issue is that you are changing the number of items in the collection as
the procedure runs. This is sort of like moving the goal posts after a game
begins ;-).

Lets say you have three hyperlinks when you started running your code. Your
code deletes the first hyperlink in the first interation of the loop. Then
it deletes the second hyperlink on the next interation. Well while it was
looping Word reindexed the hyperlinks in the collection and the second
hyperlink became the first and the third became the second. A For Each loop
doesn't look back so therefore the macro ran to completiong leaving the
middle hyperlink unchanged.

If you attempt Pesach's code modified to run forward, the same sort of thing
happens but the compilier will throw an error:

Sub ConvertHyperlinksToText()
Dim i As Long
With ActiveDocument
For i = 1 To .Hyperlinks.Count
.Hyperlinks(i).Delete
Next
End With
End Sub

If you stepped through this code using the F8 key you would see that Word
deletes the first indexed hyplerlink (then reindexes the hyperlinks left in
the collection), then deletes the second indexed hyperllink (the original
third has become the second) leaving the new first untouched (the original
second became the new first) then tries to delete the third which doesn't
exists and throws the error.

Pesach's code is designed to delete the last hyperlink in the collection and
continue this until they are all gone.

In general, to delete all the objects from a collection in VBA, you need a
For loop that iterates through the collection in descending order. The
first
of the following macros converts all the hyperlinks in the active document
to
ordinary text, and the second macro completely erases all the hyperlinks. [snip]
Hope this helps,

Indeed it does, although I don't understand how your second macro is
different from mine in the end. I thought a For Each loop in a
collection would iterate through all objects of that collection. Your
goes backwards, but why does it make a difference?

Many thanks for your help!

Raph
 
P

Pesach Shelnitz

Hi Raph,

Every object in a collection has an index. When you delete an object, the
indices of the remaining objects change (decrease by 1). Thus, when the code
goes to look for the object with the index 2, it won't look for the object
with the index 1 anymore even though there is such an object. The solution is
to start with the highest index and work backwards.

--
Hope this helps,
Pesach Shelnitz
My Web site: http://makeofficework.com


mrgou said:
In general, to delete all the objects from a collection in VBA, you need a
For loop that iterates through the collection in descending order. The first
of the following macros converts all the hyperlinks in the active document to
ordinary text, and the second macro completely erases all the hyperlinks. [snip]
Hope this helps,

Indeed it does, although I don't understand how your second macro is
different from mine in the end. I thought a For Each loop in a
collection would iterate through all objects of that collection. Your
goes backwards, but why does it make a difference?

Many thanks for your help!

Raph
.
 
M

mrgou

<I thought a For Each loop in a collection would iterate through all objects
of that collection ...
The issue is that you are changing the number of items in the collection as
the procedure runs.  This is sort of like moving the goal posts after agame
begins ;-).

Got it now. And I learned something in the process.

Thanks!

Raph
 
M

mrgou

Hi Raph,

Every object in a collection has an index. When you delete an object, the
indices of the remaining objects change (decrease by 1). Thus, when the code
goes to look for the object with the index 2, it won't look for the object
with the index 1 anymore even though there is such an object. The solution is
to start with the highest index and work backwards.

Many thanks for the help and explanation!

Raph
 
J

Jonathan West

Pesach Shelnitz said:
Hi Raph,

In general, to delete all the objects from a collection in VBA, you need a
For loop that iterates through the collection in descending order. The
first
of the following macros converts all the hyperlinks in the active document
to
ordinary text, and the second macro completely erases all the hyperlinks.

Sub ConvertHyperlinksToText()
Dim i As Long

With ActiveDocument
For i = .Hyperlinks.Count To 1 Step -1
.Hyperlinks(i).Delete
Next
End With
End Sub

Sub DeleteHyperlinks()
Dim i As Long

With ActiveDocument
For i = .Hyperlinks.Count To 1 Step -1
.Hyperlinks(i).Range.Delete
Next
End With
End Sub


In fact, if you have a large number of hyperlinks to delete, the following
versions will be somewhat faster. You probably won't notice much difference
unless there are hundreds or even thousands of hyperlinks in a document.

Sub ConvertHyperlinksToText()
Dim i As Long

With ActiveDocument
For i = 1 to .Hyperlinks.Count
.Hyperlinks(1).Delete
Next
End With
End Sub

Sub DeleteHyperlinks()
Dim i As Long

With ActiveDocument
For i = 1 to .Hyperlinks.Count
.Hyperlinks(1).Range.Delete
Next
End With
End Sub


The code looks a bit odd - repeatedly deleting the first link - but it works
because you are repeatedly deleting the first hyperlink in the document from
among those that remain after the last deletion.

The reason it is faster is that accessing the first member of a collection
is almost always faster than accessing the last, and the speed advantage
increases with the number of items in the collection.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top