Find.Execute() is always false; find.Found is never true

O

OughtFour

I'm failing to get this statement

Do While .Execute(Replace:=wdReplaceAll)
loop

to run until there is nothing left to replace. (More complete example below,
but this is the crux of the matter.)

I've tried using .Found for the same purpose. It always evaluates as false,
even though the macro makes the replacement in the document.

The problem exists in Office 97 and also in Office v.X, which use more or
less the same version of vba.

Now I've googled the usenet archives and found several examples of people
enthusiastically recommending this kind of loop. None describing any
problems doing so.

So it seems likely that I'm just making some hideously stupid mistake. But,
I give up. Can anyone tell me what the mistake is?

More-complete example--

Sub Despacify()
With ActiveDocument.Content.Find
.Wrap = wdFindContinue
.Forward = True
.ClearFormatting
.Replacement.ClearFormatting
.Format = False

'read away extra spaces
.Text = " ^p"
.Replacement.Text = "^p"
Do While .Execute(Replace:=wdReplaceAll)
Loop
End With
End Sub

By the way: I can't use a wildcard search for this purpose because I am
developing for both Windows and OS X. Office for X does not support many
wildcard searches.

Thanks for any advice!
 
K

Klaus Linke

Hi,

If you don't mind deleting non-breaking spaces and tabs at the end of the
paragraph:
How about replacing ^w^p with ^p? Doesn't require "real" wildcards ;-)

About your code: One problem that's obvious is that you do .ClearFormatting
*after* you set the parameters.

But I guess the problem may be deeper. I have a problem understanding what
ActiveDocument.Content.Find is supposed to do.
I've seen this kind of code before, and it sometimes works.
Selection.Find selects the found text, myRange.Find sets myRange to the
found text.
But what is ActiveDocument.Content.Find supposed to do? It can't very well
set the range of ActiveDocument.Content to the found text?
So there may be a basic problem with this type of construct.

I'd use Selection.Find instead. In a macro, it will only search
ActiveDocument.Content anyway, and there isn't a speed advantage or other
advantage gained by using a Range.

Greetings,
Klaus
 
J

Jonathan West

OughtFour said:
I'm failing to get this statement

Do While .Execute(Replace:=wdReplaceAll)
loop

to run until there is nothing left to replace. (More complete example below,
but this is the crux of the matter.)

The reason this works the way it does that Replace:=wdReplaceAll means that
the find/replace process continues until it can't find anything. At that
point, the Execute method ends, and because it ended with not being able to
find anything, it returns the value False.

..Execute(Replace:=wdReplaceAll)

is functuionally equivalent in all respects (except perhaps performance) to
this

Do While .Execute(Replace:=wdReplaceOne)
Loop

Now look at that loop, and ask yourself what will be the value returned by
Execute at the point it drops out of the loop. Yup, it's False!
I've tried using .Found for the same purpose. It always evaluates as false,
even though the macro makes the replacement in the document.

That is because the Found property returns the value returned by the last
time the Execute macro ran
The problem exists in Office 97 and also in Office v.X, which use more or
less the same version of vba.

Now I've googled the usenet archives and found several examples of people
enthusiastically recommending this kind of loop. None describing any
problems doing so.

So it seems likely that I'm just making some hideously stupid mistake. But,
I give up. Can anyone tell me what the mistake is?

Hopefully the above has explained the problem.
More-complete example--

Sub Despacify()
With ActiveDocument.Content.Find
.Wrap = wdFindContinue
.Forward = True
.ClearFormatting
.Replacement.ClearFormatting
.Format = False

'read away extra spaces
.Text = " ^p"
.Replacement.Text = "^p"
Do While .Execute(Replace:=wdReplaceAll)
Loop
End With
End Sub

OK, there is an alternative. What you are doing here is replacing a string
with a shorter string. This means that the number of Characters in the
document will change if the Find found anything, and you can use this
difference in the length of the document to test the exit condition for the
loop, like this

Sub Despacify()
Dim i as Long
With ActiveDocument.Content.Find
.Wrap = wdFindContinue
.Forward = True
.ClearFormatting
.Replacement.ClearFormatting
.Format = False

'read away extra spaces
.Text = " ^p"
.Replacement.Text = "^p"
Do
i = ActiveDocument.Content.Characters.Count
.Execute Replace:=wdReplaceAll
Loop Until i = ActiveDocument.Content.Characters.Count
End With
End Sub

--
Regards
Jonathan West - Word MVP
MultiLinker - Automated generation of hyperlinks in Word
Conversion to PDF & HTML
http://www.multilinker.com
 
O

OughtFour

Thanks to both Klaus and Jonathan for their advice.

Jonathan's workaround does the trick, though for various reasons I prefer
this one

Do while .Execute()
.Execute Replace:=wdReplaceAll
Loop

I worked that out when I found that the .Execute() expression evaluates as
expected when it takes no arguments.

Jonathan West wrote that
.Execute(Replace:=wdReplaceAll)

is functuionally equivalent in all respects (except perhaps performance) to
this

Do While .Execute(Replace:=wdReplaceOne)
Loop

On my Windows 98 PC, running Office 97, this is not the case.
.Execute(Replace:=wdReplaceAll)
performs the replace operation on the entire range or selection, but only
once. It is possible that would leave some strings not replaced. Thus the
need for an iterative loop.

But, I do finally understand (and am grateful for!) your explanation of why
.Execute(Replace:=wdReplaceOne)
logically evaluates as False.

Klaus said:
But what is ActiveDocument.Content.Find supposed to do? It can't very well
set the range of ActiveDocument.Content to the found text?

ActiveDocument.Content is a .Story, a type of range object. You can't reset
it, although if you assign it to a variable you can redefine the variable.

I just used it in my example, though mostly I will be running these routines
in every story in the document, using Scott Mathewman's excellent algorithm
for that purpose.

Thanks again! To summarize what I have learned, .Execute() always returns
False if it takes an argument, at least a Replace argument. Otherwise, I
think it behaves as per the documentation.
 
J

Jonathan West

OughtFour said:
Thanks to both Klaus and Jonathan for their advice.

Jonathan's workaround does the trick, though for various reasons I prefer
this one

Do while .Execute()
.Execute Replace:=wdReplaceAll
Loop

I worked that out when I found that the .Execute() expression evaluates as
expected when it takes no arguments.

the reason this works is that it is searching *again* to see if there is
anything else to replace, but not replacing anything at this time. Then if
it finds something, it goes into the loop again and does another replace
all.

Jonathan West wrote that


On my Windows 98 PC, running Office 97, this is not the case.
.Execute(Replace:=wdReplaceAll)
performs the replace operation on the entire range or selection, but only
once. It is possible that would leave some strings not replaced. Thus the
need for an iterative loop.

That is how it is designed to work. It goes though the entire range once
replacing everything until it gets to the end and there are no more
examples. The fact that after the replacements, there are now more examples
of the string higher up is not detected, and so that is why a ReplaceAll
always returns False
But, I do finally understand (and am grateful for!) your explanation of why
.Execute(Replace:=wdReplaceOne)
logically evaluates as False.

Nope, *that* can sometimes evaluate to True!
ActiveDocument.Content is a .Story, a type of range object. You can't reset
it, although if you assign it to a variable you can redefine the variable.
true


I just used it in my example, though mostly I will be running these routines
in every story in the document, using Scott Mathewman's excellent algorithm
for that purpose.

Thanks again! To summarize what I have learned, .Execute() always returns
False if it takes an argument, at least a Replace argument. Otherwise, I
think it behaves as per the documentation.

No, it always returns False if it has Replace:=wdReplaceAll. On other
occasions i might return True or False as circumstances dictate.

--
Regards
Jonathan West - Word MVP
MultiLinker - Automated generation of hyperlinks in Word
Conversion to PDF & HTML
http://www.multilinker.com
 

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