PDA

View Full Version : SetRange Results ??



MWE
09-05-2008, 12:26 PM
In my continuing battle with Word2003 and the SetRange command, I have encountered another strange situation. In this particular case, I am trying to change a particular character string in a paragraph from, say, "abc" to "def"

Using the Replace command, e.g., Para.Range.Text = Replace(Para.Range.Text,"abc","def")seems obvious and does replace the text, but it also destroys any formatting in the paragraph. So I am using a Range object to change "abc" to "def"I1 = (magically found start position of "abc"}
I2 = I1 + 2
Set wrdRange = ActiveDocument.Range(I1, I2)
wrdRange.Text = "def"This works fine. wrdRange.Text is initially "abc" and is then "def". And any formatting in the paragraph is retained.

That is unless "abc" happens to have an associated hyperlink. Then wrdRange inherits the hyperlink and wrdRange.Text is not initially = "abc". Rather, it appears to be equal to some portion of the hyperlink information and the subsequent setting of wrdRange.Text to "def" has no impact on the "abc" text in the para nor does it seem to have any effect on the hyperlink.
Is this correct? It is easy to test for the case of a hyperlink, but what do I do to change "abc" to "def"?

TonyJollans
09-05-2008, 01:00 PM
You need to understand that, behind the scenes as it were, there is a long string of data that includes more than just the text you can see. It does not include formatting - that is held separately - but it does include control information for fields, such as hyperlinks.

Simplified, you might have this in your document:

this is showing this text and then this

but in the range it looks like this:

this is { HYPERLINK to somewhere | showing this text } and then this

If you change the display (with F9) to show fields, you will see this:

this is { HYPERLINK to somewhere } and then this

No matter what view you choose you never see everything all at one time, but if you use positions as parameters to a Range, or SetRange, method they represent positions in the behind-the-scenes view, when what you want is the 'visible' view.

You control what is 'visible' (note that I use 'visible' in quotes because you are working with a range, not the selection, so you don't see anything but you work as though you see it) - you control it using the TextRetrievalMode property of the Range. When you know what you are looking at you then want to use methods such as Move, MoveEnd, etc. as these will work with the (logical) view rather than the range directly.

Something on these (pseudo-)lines:

I1 = (magically found start position of "abc"}
Set wrdRange = ActiveDocument.Range(I1, I1)
wrdRange.moveend 3

Note that the default TextRetrievalMode will mirror that in t he active window and probably not need changing.

MWE
09-05-2008, 04:34 PM
Tony: thanks for the reply. I already knew (conceptually) most of what you described, i.e., that there is lots more behind the scenes. And I know most of what it is. What was a surprise is how that information is stored. It makes no sense to me to "store" that information as part of the text. Hyperlink information should be stored as attributes of the range object, not embedded in the Text The architecture of the Range object certainly does not suggest that messy mode of storage to me. But ... it is what it is.

I poked around VBA Help exploring TextRetrievalMode. Based on the example, it looks more like a masking process. In the following VAB Help example: Set aRange = Selection.Range
With aRange.TextRetrievalMode
.IncludeHiddenText = False
.IncludeFieldCodes = False
End With
MsgBox aRange.Text I would assume that when aRange.Text is displayed, the hidden text and field codes would not be "visible". In my version of Word, those statements do nothing, i.e., the hidden text is still there.

I am still confused about the examination of Range.Text. If I use Instr to scan Range.Text for "abc", it behaves exactly as if the is no hidden text, no hidden field codes, etc. Why? Similarly, Replace works and does not appear to alter the hidden text (just the format) Why?

I do not understand what the pseudo code you provided is supposed to do. Based on VBA Help, it should advance the end 3 "counts" of unit=characters. In my test case, it advances the "end" 19 characters. There is nothing magic in that number of characters or that position (as best I can tell).

So, back to my earlier question:
I have a paragraph in which is the text "abc". That text has a hyperlink attached. Given Para.Range, how do I find "abc" and then change that to "def" without screwing up the paragraph's formatting or the hyperlink attached to "abc"

TonyJollans
09-05-2008, 11:47 PM
Yes, TextRetrievalMode is, effectively, a mask, and the only time the mask is not used is when you explicitly use Range Start and Range End positions. So, when using Range.Text, as in your InStr case, you are not using a start or end position so you see the filtered text.

Whether or not fields (including hyperlinks) should be held in line is really a moot point: that design decision was made long ago and far away. You should really consider the start and end points more as labels, or markers, than as meaningful numbers (like windows handles, say).

MoveEnd - and other related methods - work with objects that reflect what is 'visible' in the range; in the example case they are working with Character objects and normal character objects may occupy multiple bytes in the range, depending on the format used for storage, about which neither you nor I need care.

Surrogate pairs, for example, used for some far eastern characters in unicode, may use four bytes (assuming UCS2 is being used). I don't know whether you know anything about this but the point is you shouldn't need to - just consider the start and end positions, as already said, as labels without any other inherent meaning and let Word get on and manage what is actually being done to present the data to you.

So back to your original question. Once again, a full answer could be very complicated but by using Range.MoveEnd 3 you can do it in this case - or use Find & Replace and let Word worry about the finer details.

MWE
09-06-2008, 05:38 PM
Tony, thanks for you reply and suggestions. As often happens, I decided to attack this problem from a different perspective and came up with a better and more broadly useful solution.

fumei
09-07-2008, 05:28 AM
Using the Replace command, e.g.,


Para.Range.Text = Replace(Para.Range.Text,"abc","def")
seems obvious and does replace the text, but it also destroys any formatting in the paragraph.

This is not the case with proper use of Styles.