PDA

View Full Version : Solved: Problem with GoToNext(what:=wdGoToSpellingError)



Howard Kaikow
04-06-2005, 06:24 AM
I am using Word 2003 for this problem. I have not tried with earlier versions.

Using the code below, where rngError is of type Word.Range, strError is of type string and lngLastStart is of type Long, I find that the GoToNext fails when there is punctuation (e.g., comma, period, or slash) immediately after the spelling error.

In that case, one of two things happens:

1. If the spelling error is the first word in the document, that spelling error is found, but no others are found.
2. If the spelling error is not the first word in the document, then all spelling errors up to, but not including that error, are found, and no errors after that spelling error are found.

I did not find anything in the MSFT KB on this issue.

The same problem occurs if I use GoToNext with the Range object, instead of the Selection object.

The problem does not occur using the ProofReadingErrors collection, only when navigating with GoToNext(what:=wdGoToSpellingError).

Any ideas on a workaround, without using the ProofReadingErrors collection?


lngLastStart = -1
Do
Set rngError = Selection.GoToNext(what:=wdGoToSpellingError)
With rngError
If .Start = lngLastStart Then
Exit Do
End If
strError = .Text
lngLastStart = .Start
.Collapse direction:=wdCollapseEnd
.Select
End With
Loop

MOS MASTER
04-06-2005, 01:21 PM
Hi Howard, :D

Not shure why you don't want to use the "ProofreadingErrors collection" but that isn't the question here..

Why the selection Object is failing you is a miracle to me but I would say it's properly one of the many 'bugs' in Word Selection Object who I think is not reliable...:( (like the Range Object...)

For me selection would not be the way to go..if it's speed you're after (Guess not using the Selection Object) you'd be better off using the old WordBasic stuff:
WordBasic.NextMisspelling
If not please tell a little bit more of what you're trying to do here? (are you testing Word's abilities of the selection Object?..remender you doing more off that stuff) ;)

Perhaps I can play along with this quest!

Enjoy!

Howard Kaikow
04-06-2005, 04:06 PM
Hi Howard, :D

Not shure why you don't want to use the "ProofreadingErrors collection" but that isn't the question here..

That would a topic for another thread and I do not wish to digress from my question.


Why the selection Object is failing you is a miracle to me but I would say it's properly one of the many 'bugs' in Word Selection Object who I think is not reliable...:( (like the Range Object...)

For me selection would not be the way to go..

I also prefer the Range object, and I did point out in my posting that the identical problem occurs with the Range object.


if it's speed you're after (Guess not using the Selection Object) you'd be better off using the old WordBasic stuff:

WordBasic.NextMisspelling

I'd have to investigate whether that would work for my intended app, but that's a separate topic.


If not please tell a little bit more of what you're trying to do here? (are you testing Word's abilities of the selection Object?..remender you doing more off that stuff) ;)

I am trying to find out why this use of GoToNext, both with the Selection and Range objects, is not working as expected.

TonyJollans
04-06-2005, 05:22 PM
Presumably you have more code than that posted in order to know what's happening (or are you just stepping through?).

I cut and pasted your code - added dims as you state - and it all worked perfectly for me in 2003.

Howard Kaikow
04-06-2005, 10:47 PM
Presumably you have more code than that posted in order to know what's happening (or are you just stepping through?).

I cut and pasted your code - added dims as you state - and it all worked perfectly for me in 2003.

The code fails to list all errors only when there's certain punctuation immediately following a spelling error.

I am able to reproduce the problem with Word 97, Word 2000, Word 2002 and Word 2003.

In Word 2003, I deleted Normal.dot and the Word Data key in the registry, so even with default settings the problem persists.

Below are a test file I've been (ab)using, followed a cleaner version of the test code.

The spelling errors that should be listed are:
aq
Aq
qA
Hmmmmmmmmmmmm
iso
Hmmmmmmmmmmmm
iso
CheckSpellingErrors

Due to the punctuation immediately following some of those words, not all spelling errors get listed by the code below.

The simplest test is to placed a Full Stop immediately after the "aq".
Run the code.
Then insert a space prior to the Full Stop and run the code again.

I'm going to boot to my Office XP system and try things there.


aq Aq

qA

AQ



Option Explicit

' Include the following in a document and run each of the subs below

' Hmmmmmmmmmmmm, the last word in this line is lower case, iso.



' Include the following in a document and run each of the subs below

' Hmmmmmmmmmmmm, the last word in this line is lower case, iso.



Private Sub CheckSpellingErrors()

End Sub




Option Explicit
Public Sub NewSimpler()
Dim rngError As Word.Range
Dim lngLastStart As Long
Dim strError As String

System.Cursor = wdCursorWait
Application.ScreenUpdating = False

With ActiveDocument
.SpellingChecked = False
End With
Selection.HomeKey unit:=wdStory, Extend:=wdMove
lngLastStart = -1
Do
Set rngError = Selection.GoTo(what:=wdGoToSpellingError, which:=wdGoToNext)
With rngError
If .Start = lngLastStart Then
Exit Do
End If
strError = .Text
lngLastStart = .Start
.Select
Debug.Print .Start, .End, strError
End With
Loop

Set rngError = ActiveDocument.Content
lngLastStart = -1
Do
Set rngError = rngError.GoTo(what:=wdGoToSpellingError, which:=wdGoToNext)
With rngError
If .Start = lngLastStart Then
Exit Do
End If
strError = .Text
lngLastStart = .Start
Debug.Print .Start, .End, strError
End With
Loop

Selection.HomeKey unit:=wdStory, Extend:=wdMove
lngLastStart = -1
Do
Set rngError = Selection.GoToNext(what:=wdGoToSpellingError)
With rngError
If .Start = lngLastStart Then
Exit Do
End If
strError = .Text
lngLastStart = .Start
.Select
Debug.Print .Start, .End, strError
End With
Loop

Set rngError = ActiveDocument.Content
lngLastStart = -1
Do
Set rngError = rngError.GoToNext(what:=wdGoToSpellingError)
With rngError
If .Start = lngLastStart Then
Exit Do
End If
strError = .Text
lngLastStart = .Start
Debug.Print .Start, .End, strError
End With
Loop
Application.ScreenUpdating = False
System.Cursor = wdCursorNormal
Set rngError = Nothing
End Sub

TonyJollans
04-07-2005, 12:24 AM
I don't know why but, from a quick test, the code which makes the difference is:

ActiveDocument.SpellingChecked=False

With it, it seems to work as you say. Without it, it seems to work correctly.

MOS MASTER
04-07-2005, 11:12 AM
I don't know why but, from a quick test, the code which makes the difference is:

ActiveDocument.SpellingChecked=False

With it, it seems to work as you say. Without it, it seems to work correctly.
Hi Tony, :D
Simple but effective solution...but I cannot understand it!


@Howard

Some strange things:

* When executed on the lines off code provided till the last ?iso? the debugging stops at the first hmmmmm

* If instead off execution you step through the code al goes well???? (First thought of some time execution problem but DoEvents or a timer didn?t improve execution)

* Put a loop counter in and noted that stepping returns a count off 7 and is correct on debugging?Execution gives a count of 4 so somewhere the line the range object gets confused and returns .Start = lngLastStart so the sub exits?

* The real strange thing is that it always ends in the same place..(first hmmmm) at least there's a patern...

I don?t know if it still?s word investigating because Tony?s solution does work wonders on you?re code..

Hope this was helpful. :thumb

Howard Kaikow
04-07-2005, 02:32 PM
I don't know why but, from a quick test, the code which makes the difference is:

ActiveDocument.SpellingChecked=False

With it, it seems to work as you say. Without it, it seems to work correctly.

I reconstructed the code to test several cases. See code below.

Case 0 is the same result as previous code.

In case 1, force a spelling check and list the ProofReadingErrors collection. Even tho the collection is correctly listed, nanigation using wdGoToSpellingError has th eproblems I indicated.

How can the ProofReadingErrors collection be correct, yet the navigation fail, this is the mystery?

In case 2, I disable the spell checking result, so no values are returned. This is correct.

In case 3, as I have still disabled spellchecking, no values are returned. This is correct.

In case 4, I re-enable spell checking, but do not recreate the ProofReadingErrors collection. The result is the same as in case 1, where I did recreate the ProofReadingErrors collection. This seems to indicate that it does not matter whether the ProofReadingErrors collection has been created before navigating with wdGoToSpellingError.

Case 5 produces the same result as case 1



Option Explicit
Public Sub NewSimpler()
Dim rngError As Word.Range
Dim yourErrors As Word.ProofreadingErrors

System.Cursor = wdCursorWait
Application.ScreenUpdating = False

Debug.Print "11111111111111111111111111111"
With ActiveDocument
.SpellingChecked = False
Set yourErrors = .SpellingErrors
End With
If yourErrors.Count = 0 Then
Debug.Print "No spelling errors found."
Else
For Each rngError In yourErrors
Debug.Print "From Spelling Errors: " & rngError.Start, rngError.Text
Next
End If
ListSpellingErrors

Debug.Print "22222222222222222222222222222"
ActiveDocument.SpellingChecked = True
ListSpellingErrors

Debug.Print "33333333333333333333333333333"
Set yourErrors = ActiveDocument.SpellingErrors
If yourErrors.Count = 0 Then
Debug.Print "No spelling errors found."
Else
For Each rngError In yourErrors
Debug.Print "From Spelling Errors: " & rngError.Start, rngError.Text
Next
End If
ListSpellingErrors

Debug.Print "44444444444444444444444444444"
ActiveDocument.SpellingChecked = False
ListSpellingErrors

Debug.Print "55555555555555555555555555555"
Set yourErrors = ActiveDocument.SpellingErrors
If yourErrors.Count = 0 Then
Debug.Print "No spelling errors found."
Else
For Each rngError In yourErrors
Debug.Print "From Spelling Errors: " & rngError.Start, rngError.Text
Next
End If
ListSpellingErrors

ActiveDocument.Saved = True
Application.ScreenUpdating = False
System.Cursor = wdCursorNormal
Set yourErrors = Nothing
End Sub

Private Sub ListSpellingErrors()
Dim rngError As Word.Range
Dim lngLastStart As Long
Dim strError As String

Selection.HomeKey unit:=wdStory, Extend:=wdMove
lngLastStart = -1
Do
Set rngError = Selection.GoTo(what:=wdGoToSpellingError, which:=wdGoToNext)
With rngError
If .Start = lngLastStart Then
Exit Do
End If
strError = .Text
lngLastStart = .Start
.Select
Debug.Print .Start, .End, strError
End With
Loop

Set rngError = ActiveDocument.Content
lngLastStart = -1
Do
Set rngError = rngError.GoTo(what:=wdGoToSpellingError, which:=wdGoToNext)
With rngError
If .Start = lngLastStart Then
Exit Do
End If
strError = .Text
lngLastStart = .Start
Debug.Print .Start, .End, strError
End With
Loop

Selection.HomeKey unit:=wdStory, Extend:=wdMove
lngLastStart = -1
Do
Set rngError = Selection.GoToNext(what:=wdGoToSpellingError)
With rngError
If .Start = lngLastStart Then
Exit Do
End If
strError = .Text
lngLastStart = .Start
.Select
Debug.Print .Start, .End, strError
End With
Loop

Set rngError = ActiveDocument.Content
lngLastStart = -1
Do
Set rngError = rngError.GoToNext(what:=wdGoToSpellingError)
With rngError
If .Start = lngLastStart Then
Exit Do
End If
strError = .Text
lngLastStart = .Start
Debug.Print .Start, .End, strError
End With
Loop
Set rngError = Nothing
End Sub

MOS MASTER
04-07-2005, 02:47 PM
Hi Howard, :D

Very nice test code!

I'll play with it some more tommorow and I'll hope someone has the answere to you're query....(But perhaps it's just one of the selection object's strange habbits that you've discovered)

Enjoy! ;)

Howard Kaikow
04-07-2005, 03:12 PM
Hi Howard, :D

Very nice test code!

I'll play with it some more tommorow and I'll hope someone has the answere to you're query....(But perhaps it's just one of the selection object's strange habbits that you've discovered)

Enjoy! ;)

selection object is not the issue.
same problem using range object.

MOS MASTER
04-07-2005, 03:54 PM
selection object is not the issue.
same problem using range object.
Yes you've mentioned this before...but you're misunderstanding me.

I'll explain the MSDN says:
GoToNext Method


Returns a Range object that refers to the start position of the next item or location specified by the What argument. If you apply this method to the Selection object, the method moves the selection to the specified item (except for the wdGoToGrammaticalError, wdGoToProofreadingError, and wdGoToSpellingError constants). Range object.

Note When you use this method with the wdGoToGrammaticalError, wdGoToProofreadingError, or wdGoToSpellingError constant, the Range object that's returned includes any grammar error text or spelling error text.This means to me that this method is using the constant wdGoToSpellingError in a different way. (Seams todo what is expected but perhaps there's more than the eye can see)

Maybe this one of the reasons why something is failing..not saying it is...perhaps! ;)

Enjoy.

Howard Kaikow
04-07-2005, 07:08 PM
Using either Selection or Range with wdGoToSpellingError, the item returned is always a range object containing the spelling error.

Howard Kaikow
04-07-2005, 11:01 PM
The following is a better statement of the problem and generates test cases.



Option Explicit
' Author: Howard Kaikow
' Author URL: http://www.standards.com/
' Date: April 2005
Private docNew As Word.Document
Private yourErrors As Word.ProofreadingErrors
Private Sub wdGoToSpellingErrorBug()
' Purpose: This code demonstrates the problem described below.
' The code generates test documents and displays results using Debug.Print.
' The generated documents are not saved.

' Problem: Navigating through a document using GoToNext or GoTo with wdGoToSpellingError
' fails to find all spelling errors if there is punctuation (e.g., comma, period, or slash)
' immediately after any of the spelling errors in the document.

' The problem occurs using either the Range or Selection objects.

' The problem does not occur using the ProofReadingErrors collection, only
' when navigating with wdGoToSpellingError.

' Word versions: The problem exists in Word 97, Word 2000, Word 2002 and Word 2003.

' Problem behavior:
' 1. If a spelling error, with immediately following punctuation, is the first word in the document,
' that spelling error is found, but no others are found.

' 2. If a spelling error, with immediately following punctuation, is not the first word in the document,
' then all spelling errors up to, but not including that error, are found, and no
' errors after that spelling error are found.

System.Cursor = wdCursorWait
Application.ScreenUpdating = False

IncorrectResults ' These tests produce incorrect results
CorrectResults ' These tests produce correct results

Application.ScreenUpdating = False
Set docNew = Nothing
System.Cursor = wdCursorNormal
Set yourErrors = Nothing
End Sub

Private Sub IncorrectResults()
Dim rngError As Word.Range
Debug.Print "Incorrect-0"
CreateDocPunctuation
ListSpellingErrors
DeleteDoc

Debug.Print "Incorrect-1"
CreateDocPunctuation
docNew.SpellingChecked = False
ListSpellingErrors
DeleteDoc

Debug.Print "Incorrect-2"
CreateDocPunctuation
With docNew
.SpellingChecked = False
Set yourErrors = .SpellingErrors
End With
If yourErrors.Count = 0 Then
Debug.Print "No spelling errors found."
Else
For Each rngError In yourErrors
Debug.Print "From Spelling Errors: " & rngError.Start, rngError.Text
Next
End If
ListSpellingErrors
DeleteDoc

Debug.Print "Incorrect-3"
CreateDocPunctuation
docNew.SpellingChecked = True
ListSpellingErrors
DeleteDoc

Debug.Print "Incorrect-4"
CreateDocPunctuation
Set yourErrors = docNew.SpellingErrors
If yourErrors.Count = 0 Then
Debug.Print "No spelling errors found."
Else
For Each rngError In yourErrors
Debug.Print "From Spelling Errors: " & rngError.Start, rngError.Text
Next
End If
ListSpellingErrors
DeleteDoc

Debug.Print "Incorrect-5"
CreateDocPunctuation
docNew.SpellingChecked = False
ListSpellingErrors
DeleteDoc

Debug.Print "Incorrect-6"
CreateDocPunctuation
Set yourErrors = docNew.SpellingErrors
If yourErrors.Count = 0 Then
Debug.Print "No spelling errors found."
Else
For Each rngError In yourErrors
Debug.Print "From Spelling Errors: " & rngError.Start, rngError.Text
Next
End If
ListSpellingErrors
DeleteDoc
End Sub

Private Sub CorrectResults()
Dim rngError As Word.Range
Debug.Print "Correct-0"
CreateDocNoPunctuation
ListSpellingErrors
DeleteDoc

Debug.Print "Correct-1"
CreateDocNoPunctuation
docNew.SpellingChecked = False
ListSpellingErrors
DeleteDoc

Debug.Print "Correct-2"
CreateDocNoPunctuation
With docNew
.SpellingChecked = False
Set yourErrors = .SpellingErrors
End With
If yourErrors.Count = 0 Then
Debug.Print "No spelling errors found."
Else
For Each rngError In yourErrors
Debug.Print "From Spelling Errors: " & rngError.Start, rngError.Text
Next
End If
ListSpellingErrors
DeleteDoc

Debug.Print "Correct-3"
CreateDocNoPunctuation
docNew.SpellingChecked = True
ListSpellingErrors
DeleteDoc

Debug.Print "Correct-4"
CreateDocNoPunctuation
Set yourErrors = docNew.SpellingErrors
If yourErrors.Count = 0 Then
Debug.Print "No spelling errors found."
Else
For Each rngError In yourErrors
Debug.Print "From Spelling Errors: " & rngError.Start, rngError.Text
Next
End If
ListSpellingErrors
DeleteDoc

Debug.Print "Correct-5"
CreateDocNoPunctuation
docNew.SpellingChecked = False
ListSpellingErrors
DeleteDoc

Debug.Print "Correct-6"
CreateDocNoPunctuation
Set yourErrors = docNew.SpellingErrors
If yourErrors.Count = 0 Then
Debug.Print "No spelling errors found."
Else
For Each rngError In yourErrors
Debug.Print "From Spelling Errors: " & rngError.Start, rngError.Text
Next
End If
ListSpellingErrors
DeleteDoc
End Sub

Private Sub CreateDocNoPunctuation()
Set docNew = Documents.Add
With docNew.Content
.InsertAfter "kerect"
.InsertParagraphAfter
.InsertAfter "purrfect"
.InsertParagraphAfter
.InsertAfter "absolutivily"
End With
End Sub

Private Sub CreateDocPunctuation()
Set docNew = Documents.Add
With docNew.Content
.InsertAfter "kerect."
.InsertParagraphAfter
.InsertAfter "purrfect"
.InsertParagraphAfter
.InsertAfter "absolutivily"
End With
End Sub

Private Sub CreateOriginalPunctuation() ' Currently not used
Set docNew = Documents.Add
With docNew.Content
.InsertAfter "aQ"
.InsertParagraphAfter
.InsertAfter "Aq"
.InsertParagraphAfter
.InsertAfter "qA"
.InsertParagraphAfter
.InsertAfter "AQ"
.InsertParagraphAfter
.InsertParagraphAfter
.InsertAfter "Option Explicit"
.InsertParagraphAfter
.InsertAfter "' Include the following in a document and run each of the subs below"
.InsertParagraphAfter
.InsertAfter "' Hmmmmmmmmmmmm, the last word in this line is lower case, iso."
.InsertParagraphAfter
.InsertParagraphAfter
.InsertAfter "' Include the following in a document and run each of the subs below."
.InsertParagraphAfter
.InsertAfter "' Hmmmmmmmmmmmm, the last word in this line is lower case, iso."
.InsertParagraphAfter
.InsertParagraphAfter
.InsertAfter "Private Sub CheckSpellingErrors()"
.InsertParagraphAfter
.InsertAfter " End Sub"
End With
End Sub

Private Sub DeleteDoc()
With docNew
.Saved = True
.Close
End With
End Sub

Private Sub ListSpellingErrors()
Dim rngError As Word.Range
Dim lngLastStart As Long
Dim strError As String

docNew.Activate
Selection.HomeKey unit:=wdStory, Extend:=wdMove
lngLastStart = -1
Do
Set rngError = Selection.GoTo(what:=wdGoToSpellingError, which:=wdGoToNext)
With rngError
If .Start = lngLastStart Then
Exit Do
End If
strError = .Text
lngLastStart = .Start
.Select
Debug.Print .Start, .End, strError
End With
Loop

Set rngError = docNew.Content
lngLastStart = -1
Do
Set rngError = rngError.GoTo(what:=wdGoToSpellingError, which:=wdGoToNext)
With rngError
If .Start = lngLastStart Then
Exit Do
End If
strError = .Text
lngLastStart = .Start
Debug.Print .Start, .End, strError
End With
Loop

Selection.HomeKey unit:=wdStory, Extend:=wdMove
lngLastStart = -1
Do
Set rngError = Selection.GoToNext(what:=wdGoToSpellingError)
With rngError
If .Start = lngLastStart Then
Exit Do
End If
strError = .Text
lngLastStart = .Start
.Select
Debug.Print .Start, .End, strError
End With
Loop

Set rngError = docNew.Content
lngLastStart = -1
Do
Set rngError = rngError.GoToNext(what:=wdGoToSpellingError)
With rngError
If .Start = lngLastStart Then
Exit Do
End If
strError = .Text
lngLastStart = .Start
Debug.Print .Start, .End, strError
End With
Loop
Set rngError = Nothing
End Sub

Howard Kaikow
04-08-2005, 03:43 AM
Well, I've got to disappear for a while to prepare my annual mailing to my Uncle Sam.

The only workaround I've found to the problem I posed is to move the Selection/Range past the troublesome characters. Perhaps that's what Word does internally anyway? I hate programming such hacks!

In any case, the method used to iterate the ProofReadingErrors makes a big difference.

For a recent example:

Using For Each: 68280 milliseconds
Using For Next: 42469 milliseconds

Using GoToNext or GoTo with the Range and Selection objects used (I do not recall which used what): 19826, 19950, 19857, and 19731 milliseconds.

So, you can see that it is much faster to traverse the document, instead of using the ProofReadingErrors collection.

See ya in a week or so.

ta, ta!

MOS MASTER
04-08-2005, 10:39 AM
Using either Selection or Range with wdGoToSpellingError, the item returned is always a range object containing the spelling error.
Haha, :D

Yes...I can read thank you...but perhaps something is hapening with the range that you can't see that has an effect on this problem. ;)


Well, I've got to disappear for a while to prepare my annual mailing to my Uncle Sam.

The only workaround I've found to the problem I posed is to move the Selection/Range past the troublesome characters. Perhaps that's what Word does internally anyway? I hate programming such hacks!

In any case, the method used to iterate the ProofReadingErrors makes a big difference.

For a recent example:

Using For Each: 68280 milliseconds
Using For Next: 42469 milliseconds

Using GoToNext or GoTo with the Range and Selection objects used (I do not recall which used what): 19826, 19950, 19857, and 19731 milliseconds.

So, you can see that it is much faster to traverse the document, instead of using the ProofReadingErrors collection.

See ya in a week or so.

ta, ta!
You did a great job on investigating this issue!

I still do wonder if Tony's tip actually worked for you? (Seams to work over here)

ta ta to you to! :thumb

Howard Kaikow
04-11-2005, 05:16 PM
Although the GoTo and GoToNext methods appeared to be faster than either For Each or For Next for iterating the spelling errors collection, for larger documents this may not be so.

I got the following results for 1 document, times are in milliseconds:

For Each: 286852

For Next: 180676

Range.Goto: 612035

Range.GoToNext: 507473

Selection.GoTo: 518455

Selection.GoToNext: 524448

MOS MASTER
04-12-2005, 10:56 AM
Hi, :D

Well it's been very educating to see how this works with the selection or range objects but I've always used the Errors Collection for this type off job...(And properbly will continue to do so)

Hope you had a good conversation with you're Uncle Sam? :thumb

Howard Kaikow
04-15-2005, 12:41 AM
I started this thread because I was finding that iterating thru the collection of spelling errors was very slow using For Each or For Next, and GoTo and GoToNext seemed to be much faster, but ran into a problem.

This thread seems to have proved the following:

1. Of the 4 methods for iterating the spelling errors collection, none is always better than the others. Results depend greatly on the number of spelling errors in the document, the size of the document and the constituent elements of the document.

2. Using For Each and For Next are the only "reliable" methods as the GoTo and GoToNext get tripped up in certain circumstances, e.g., when punctuation immediately follows a spelling error or when the spelling error is the result of a field. It seems that I demonstrated that one can avoid these issues if one codes around any non-"whitespace" immediately following a spelling error.

This workaround is not documented, so I would feel uncomfortable using it in real code.

3. Since last posting in this thread, I began investigating why iterating thru the spelling errors is so slow. Seems to be an artifact of the MSFT implementation. Indeed, tonight, I moved code in the real app to a VB 6 DLL. Speed improvement was only very minor.

Examining the code below led to some interesting observations.

It only takes a few milliseconds for Word to build the collection so one can get the value of .COUNT quite quickly.

So why does it then take so long to iterate thru the collection if the collection already exists?

Each item of the collection is returned as a mere range object. I must ASSuME that the collection has a list of the ranges and it should be trivial to return the .Text for each member of the collection. However, the collection is much more than an array of ranges.

You can see in the code below, that turning off spell checking AFTER getting the collection causes the collection to be emptied, and the bulk of the time iterating thru the collection is spent merely converting each member of the collection to a range object.



Option Explicit
Private Declare Function QueryPerformanceCounter Lib "kernel32" (curPerformanceCount As Currency) As Long
Private Declare Function QueryPerformanceFrequency Lib "kernel32" (curPerformanceCount As Currency) As Long
Public Sub SpellCheckOff()
Dim i As Long
Dim lngSpellingErrorCount As Long
Dim rngError As Word.Range
Dim yourErrors As Word.ProofreadingErrors

Dim strForEach As String
Dim strForNext As String

Dim curQPStart As Currency
Dim curQPEnd As Currency
Dim curQPFreq As Currency
Dim dblQPFreq As Double
Dim lngTime As Long
Dim rngSpellingError() As Word.Range

QueryPerformanceFrequency curQPFreq
dblQPFreq = CDbl(curQPFreq)

System.Cursor = wdCursorWait

Application.ScreenUpdating = False

QueryPerformanceCounter curQPStart
With ActiveDocument
.SpellingChecked = False
' Checks only main story
Set yourErrors = .SpellingErrors
End With
QueryPerformanceCounter curQPEnd
lngTime = (curQPEnd - curQPStart) / dblQPFreq * 1000
Debug.Print "ProofReadingErrors collection: " & lngTime

QueryPerformanceCounter curQPStart
lngSpellingErrorCount = yourErrors.Count
QueryPerformanceCounter curQPEnd
lngTime = (curQPEnd - curQPStart) / dblQPFreq * 1000
Debug.Print "ProofReadingErrors collection Count: " & lngTime

' yourErrors should now contain the collection of spelling errors.

QueryPerformanceCounter curQPStart
ReDim rngSpellingError(lngSpellingErrorCount - 1)
For i = 0 To lngSpellingErrorCount - 1
Set rngSpellingError(i) = yourErrors(i + 1)
Next i
QueryPerformanceCounter curQPEnd
lngTime = (curQPEnd - curQPStart) / dblQPFreq * 1000
Debug.Print "Copying ranges from collection: " & lngTime


' Let's try disabling further spell checking.
ActiveDocument.SpellingChecked = True
' Now run the rest of the tests
QueryPerformanceCounter curQPStart
With yourErrors
For i = 0 To lngSpellingErrorCount - 1
strForNext = rngSpellingError(i).Text
Next i
End With
QueryPerformanceCounter curQPEnd
lngTime = (curQPEnd - curQPStart) / dblQPFreq * 1000
Debug.Print "Get text from ranges: " & lngTime


QueryPerformanceCounter curQPStart
lngSpellingErrorCount = yourErrors.Count
QueryPerformanceCounter curQPEnd
lngTime = (curQPEnd - curQPStart) / dblQPFreq * 1000
Debug.Print "ProofReadingErrors collection Count: " & lngTime

Debug.Print "Total spelling errors: " & CStr(lngSpellingErrorCount)

If lngSpellingErrorCount <> 0 Then
QueryPerformanceCounter curQPStart
With yourErrors
For i = 1 To lngSpellingErrorCount
strForNext = .Item(i).Text
Next i
End With
QueryPerformanceCounter curQPEnd
lngTime = (curQPEnd - curQPStart) / dblQPFreq * 1000
Debug.Print "For Next(.Item): " & lngTime

QueryPerformanceCounter curQPStart
For i = 1 To lngSpellingErrorCount
strForNext = yourErrors(i).Text
Next i
QueryPerformanceCounter curQPEnd
lngTime = (curQPEnd - curQPStart) / dblQPFreq * 1000
Debug.Print "For Next: " & lngTime

QueryPerformanceCounter curQPStart
For Each rngError In yourErrors
strForEach = rngError.Text
Next rngError
QueryPerformanceCounter curQPEnd
lngTime = (curQPEnd - curQPStart) / dblQPFreq * 1000
Debug.Print "For Each: " & lngTime
End If
ActiveDocument.Saved = True
Application.ScreenUpdating = False
System.Cursor = wdCursorNormal
Set rngError = Nothing
Set yourErrors = Nothing
End Sub

MOS MASTER
04-15-2005, 09:28 AM
Hi Howard, :D

You're really going for the botton aint you?

Well this code lookes real great so I will definitively take a crack at it and am curious on how it runs..

I think digging these things out really gets you on a higher level off knowledge because you're forced to read in to every possibillaty...

Till the next encounter..:thumb

Howard Kaikow
04-15-2005, 10:03 AM
Hi Howard, :D

You're really going for the botton aint you?

Well this code lookes real great so I will definitively take a crack at it and am curious on how it runs..

I think digging these things out really gets you on a higher level off knowledge because you're forced to read in to every possibillaty...

Till the next encounter..:thumb

I find it hard to believe that there is no efficient way to retrieve the ranges from a proofreadingerrors collection.

My main test document is a 168 page document that has 267 spelling errors. This is a real document. Only 1 of the spelling errors is really an error, all the others just are not in the dictionary.

On my very slow system, it takes less than 10 seconds for Word to construct the collection so I can retrieve .Count.

However, it then takes about 3 minutes to retrieve the ranges.

Since the object returned from the ProofReadingErrors collection is a range, there sure must be a rather complex structure in the collection to cause Word to take so much time to return the range.

Perhaps, retrieving the range causes Word to revisit each range to double check the spelling error before returning the range, in effect, rebuilding the collection each time an item is retrieved? It sure seems that way.

MOS MASTER
04-15-2005, 10:16 AM
I find that hard to believe as well!

I must mentione that I've never encountered a document that has those many word's in them that aren't in the dic or are a spelling error.

So that's why I've probably never asked my self this question because there was no need for it..

But like you it's still on my mind what a possible sollution will look like...

I'll keep on trying stuff for yah! :banghead:

Howard Kaikow
04-15-2005, 10:34 AM
Modifying my previous code to include the code below does seem to imply that any reference to a collection of ProofReadingErrors does cause the collection to be rebuilt each time.

I am trying to treat yourErrors as an already built collection and retrieving the ranges that way.

But the time for that loop is almost identical to the time for the 2nd loop in which I explicitly ask for a single member of SpellingErrors each time. In this case, Word is very likely rebuilding the collection each time.

Also, you can see the same behavior for my code samples with much smaller documents, but the absolute time differences are not as large so the issue does not get noticed unless one is looking for this type of detail.



' yourErrors should now contain the collection of spelling errors.

QueryPerformanceCounter curQPStart
ReDim rngSpellingError(lngSpellingErrorCount - 1)
For i = 0 To lngSpellingErrorCount - 1
Set rngSpellingError(i) = yourErrors(i + 1)
Next i
QueryPerformanceCounter curQPEnd
lngTime = (curQPEnd - curQPStart) / dblQPFreq * 1000
Debug.Print "Copying ranges from collection: " & lngTime

QueryPerformanceCounter curQPStart
ReDim rngSpellingError(lngSpellingErrorCount - 1)
With ActiveDocument.Content
For i = 0 To lngSpellingErrorCount - 1
Set rngSpellingError(i) = .SpellingErrors(i + 1)
Next i
End With
QueryPerformanceCounter curQPEnd
lngTime = (curQPEnd - curQPStart) / dblQPFreq * 1000
Debug.Print "Using ActiveDocument.Content, Copying ranges from collection: " & lngTime

Howard Kaikow
04-16-2005, 09:55 AM
I posted a summary of this problem in a MSFT newsgroup yesterday.

Got the expected response.

MSFT's ill conceived implementation of the ProofReadingErrors collection does appear to cause the collection to be recalculated when accessing a member of the collection.

Somebody mentioned that there is a paper on this somewhere.
If I find the paper, I'll let y'all know.

So fer now, I'll mark this thread as Solved, with a very unsatisfactory ending.

MOS MASTER
04-16-2005, 11:13 AM
Yes indeed unsatisfactory when you've spended as much time as you have! :mkay