VBA : (selective) deletion of hypertext links

Q

Quetzalcoatl

Hi,

Does anybody know why the h... the following macro is acting so strangely (Word
97/2000) ?

For Each LINK In ActiveDocument.Hyperlinks
LINK.Delete
Next

It should delete all hypertext links, but actually only delete 1 on 2, meaning
that you need to run it n+1 times for 2^n links.
If you replace "LINK.Delete" by "MsgBox LINK.Range", you can see *all* links
filing one by one.
Sure, the macro below works, but what a ploy !

StartAgain:
TMP = ActiveDocument.Hyperlinks.Count
If TMP = 0 Then Exit Sub
For I = 1 To TMP
On Error GoTo StartAgain
ActiveDocument.Hyperlinks(I).Range.Select
Selection.Delete
Next

This one below works too, but it's a bit drastic and you can't do any test on
the link before deletion (for a selective deletion).

Selection.WholeStory
Selection.Fields.Unlink

Any good idea ?

Thanks.
 
J

Jezebel

Word sometimes goes awry iterating a collection if you're deleting from the
collection at the same time. Try --

Dim pCount as long
For pCount = 1 to ActiveDocument.Hyperlinks.count
ActiveDocument.Hyperlinks(1).Delete
Next

or

On error resume next
Do
ActiveDocument.Hyperlinks(1).Delete
Loop while Err.Number = 0
On Error goto 0
 
P

Peter Hewett

Hi Quetzalcoatl

When I delete stuff from collection I generally iterate the collection from back to front
rather than front to back:

Dim lngLinks As Long

For lngLinks = ActiveDocument.Hyperlinks.Count To 1 Step -1
ActiveDocument.Hyperlinks(lngLinks).Delete
Next

HTH + Cheers - Peter


Word sometimes goes awry iterating a collection if you're deleting from the
collection at the same time. Try --

Dim pCount as long
For pCount = 1 to ActiveDocument.Hyperlinks.count
ActiveDocument.Hyperlinks(1).Delete
Next

or

On error resume next
Do
ActiveDocument.Hyperlinks(1).Delete
Loop while Err.Number = 0
On Error goto 0
 
J

Jezebel

Is there any advantage over deleting the first one repeatedly?

For lngLinks = 1 to ActiveDocument.Hyperlinks.Count
ActiveDocument.Hyperlinks(1).Delete
Next


Peter Hewett said:
Hi Quetzalcoatl

When I delete stuff from collection I generally iterate the collection from back to front
rather than front to back:

Dim lngLinks As Long

For lngLinks = ActiveDocument.Hyperlinks.Count To 1 Step -1
ActiveDocument.Hyperlinks(lngLinks).Delete
Next

HTH + Cheers - Peter
 
P

Peter Hewett

Hi Jezebel

To be quite honest your method will work just as well. But based on something I read
quite a few years ago I use the back-to-front method as I believe that it's somewhat more
efficient when dealing with a collection that contains a lot of objects.

Cheers - Peter


Is there any advantage over deleting the first one repeatedly?

For lngLinks = 1 to ActiveDocument.Hyperlinks.Count
ActiveDocument.Hyperlinks(1).Delete
Next

HTH + Cheers - Peter
 
J

Jay Freedman

I haven't timed it to be certain, but it seems that always deleting
the first one should run slightly faster, since VBA doesn't have to
count up through the collection from 1 to some (maybe large) value of
the loop counter during each iteration to find the one to be deleted.
OTOH, I don't know how VBA manages its internal lists of collection
members, and the algorithms may be optimized for random access rather
than sequential so that it wouldn't make any difference which method
you use.

If you're deleting selectively instead of deleting all, it's safer to
work from the back to the front because the act of deletion causes
some collections to renumber -- but not others, and I can never
remember which. :-(
 
J

Jezebel

My experience of trying to time these sorts of task is that you need HUGE
numbers of items to register any difference at all.
 
Q

Quetzalcoatl

Cheers guys, both are working well for what I need, I think I'll use the one
which iterates from back to front because it's more readible to me (in a few
months, will I understand why this "ActiveDocument.Hyperlinks(1).Delete" in a
loop ?).

Many thanks.
 
J

Jay Freedman

Quetzalcoatl said:
Cheers guys, both are working well for what I need, I think I'll use the one
which iterates from back to front because it's more readible to me (in a few
months, will I understand why this "ActiveDocument.Hyperlinks(1).Delete" in a
loop ?).

Many thanks.

The last question isn't hard to answer... The expression
ActiveDocument.Hyperlinks(1) always points to the first hyperlink in
the document. After you delete the first one, the hyperlink that used
to be second is now the first, and the same expression points to that
one. Delete that one, and the hyperlink that was originally third is
now the first -- and so on until there aren't any more. Since you know
at the start how many hyperlinks there are --
ActiveDocument.Hyperlinks.Count -- you know exactly how many times you
have to run the loop to delete them all.
 
W

Word Heretic

G'day "Quetzalcoatl" <[email protected]>,

The hyperlinks collection hasn't been implemented properly. If we do a
dolly step of what's happening you'll see why:

Link.Index=1
Delete Link
All links reshuffle down, link 2 becomes link 1.
Link.Index=2
Delete link
Ah look, we missed the new link 1 created by the shuffle
And so on

Thus, the better code is

With ActiveDocument.Hyperlinks
While .Count > 0
.Item(1).Delete
Wend
End With

(Its also faster too)

Steve Hudson - Word Heretic
Want a hyperlinked index? S/W R&D? See WordHeretic.com

steve from wordheretic.com (Email replies require payment)


Quetzalcoatl reckoned:
 
J

Jezebel

Thus, the better code is

With ActiveDocument.Hyperlinks
While .Count > 0
.Item(1).Delete
Wend
End With

The performance hit with this structure is that Word has to re-calculate the
Count each time. Faster still is

For pIndex = 1 to .Count
.Item(1).Delete

This works because the start and end values for a For ... Next loop are
calculated only once, at the start; so the loop iterates for the original
value of .Count.
 
W

Word Heretic

G'day "Jezebel" <[email protected]>,

Have you tried timing it? Count is referenced - not calculated - as
the With forces the calc.

Steve Hudson - Word Heretic
Want a hyperlinked index? S/W R&D? See WordHeretic.com

steve from wordheretic.com (Email replies require payment)


Jezebel reckoned:
 
J

Jezebel

OK yes, it's referenced, but it has to be referenced each time, since it
changes with each iteration. But you're right about the timing ... the
difference is unlikely to be visible to the naked stopwatch.
 

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