VBA Textrange Processing: Need help in processing multiple ranges

  • Thread starter david.f.jenkins
  • Start date
D

david.f.jenkins

I have a macro that must process each selected paragraph from a PPT
slide. It makes changes to the paragraph text - modifying it by
adding, deleting, or otherwise changing characters in the text.

My approach has been to build a set of all the text ranges in the
selection, and then process these one by one. I run into problems when
I add text to a paragraph (or sentence) - the text for that paragraph
gets shoved to the right by the number of bytes that I'm inserting.
(I'm not absolutely sure of this, but I think he stores the shifted
bytes in a bogus paragraph that he creates. Nevertheless, my original
set of text ranges doesn't contain the new paragraph.)
The bytes that get shifted off aren't lost; if I re-get all the
selected text ranges, everything is there, and refelcts all the changes
up to that point.

As I'm processing, I don't know whether I'm gaining or losing bytes in
a paragraph - it's all driven by the VBScript regex engine.

Here's my problem: if I'm on the nth original text range, and it gets
modified, and then I need to do some further processing with the
right-hand part of the text, I'm screwed - it's gone (as far as that
processing loop is concerned).

So: is there a way to "refresh" the nth textrange from a selection?
Right now I'm having to do some really unnatural acts to refresh the
entire textrange collection without losing my processing place. The
points where I'm doing that help, but there's still no guarantee that I
may not be missing some right-hand text when I apply another regex
replace. I guess I could refresh the entire textrange collection each
time I make a change, but that means I'd have to pass the index of the
current textrange along, instead of the textrange reference itself, and
then get the textrange from the collection each time I have to work on
it.

I see that this rambles, but I've lost a lot of sleep over this in the
last few nights. I hope there's a simple solution someone can point me
to. Thanks for your help.
 
S

Steve Rindsberg

Have you tried processing all of this from back to front rather than front to
back?

Example:

Here
Are
Several
Paragraphs

If you change "Are" to "Were", all of your byte offsets from that point on are
munged. Going the other way, if you change "Paragraphs" to "Extraordinarily
verbose and semantically imprecise paragraphs" .... "Are" is still at the same
byte offset when you get to it later on
 
D

david.f.jenkins

Thanks, Steve. I wish I'd thought of that earlier, but now I have so
much code that processes stuff "frontwards", that I'm very goosy about
making such massive modifications.

What I've done, and it appears to work out pretty well, is just call a
little function to repopulate my textrange collection each time I've
changed some text. It hasn't seemed to slow things down, that I can
notice. Since the code that actually makes the changes is pretty well
centralized, it was pretty easy to just add a call to refresh function
at those points.

Since all this refreshing takes place in the middle of a loop going
through the textrange collection, I'll be up the creek if the number of
ranges change as a result of any of the text changes I make. Right
now, this collection consists of all paragraphs in the selection. I
haven't quite figured out whether I'll be screwed or not if any of the
text changes I make results in a new paragrpah in the middle of the
selection (highly, highly, unlikley). Part of me says it may be all
right - if I do create a new paragraph, it will be perforce
"downstream" (has to be, I think) of where I am in the loop, so that
even after I refresh the collection, I'll bump into the new paragraph
in the next iteration. OTOH, if I've done anything predicated on the
count of items in the collection, and I create one on the fly, I may be
in trouble.

Anyway, as always, I appreciate your suggestions, Steve -- thanks again
 
S

Steve Rindsberg

Thanks, Steve. I wish I'd thought of that earlier, but now I have so
much code that processes stuff "frontwards", that I'm very goosy about
making such massive modifications.

I hear that.

But you might try copying the routine that controls the loop through the text
and renaming it or commenting it out. That backs you up.

Then change the loop from e.g.

For each Whatever in Whosis

to For X = Whosis.Whatevers.Count to 1 Step - 1

Sometimes that's all it takes.
 
D

david.f.jenkins

And I hear that.

I've got scads of loops in there - on tokens, words, sentences,
paragraphs, shapes, textranges - you name it. Rather than ferret all
those out, I'm going to go with the Q&D approach I've now got working.
This thing's due for a client demo on Wed. PM, and I'm really leery of
significant changes at this juncture.

Thanks, though, for listening on a Saturday - true dedication!

I think the root of my problem here is my understanding of a) objects
in general, and b) textranges in particular. It just seems to me that
if I play by the rules, using Replace, InsertBefore, InsertAfter, etc.,
all those changes I made to the original TextRange.text ought to be
reflected in the TextRange.Text when I get done. For a while, I
thought, well, "Maybe it's the dubuuger - he can't keep up with my
changes." But the results I got showed what I've been describing.
Anyway, all's [pretty much] well, it's late and tomorrow's Mother's Day
- so I better get to bed.

'night.
 
S

Steve Rindsberg

Rule Number 1: Go with what works
Rule Number 2: When time permits, make it work better
Rule Number 3: But never let Rule Number 2 interfere with Rule Number 1

TextRanges are strange critters, and seem to lead ephemeral lives at best.
Using .InsertBefore, for example, returns a text range containing the text you
inserted, not the original text.

Something like:

Set oOriginalRange = ActiveWindow.Selection.TextRange
Set oNewRange = oOriginalRange.InsertBefore("My New Text")

Debug.Print oOriginalRange.Text ' gives you My New Text+original text in range
Debug.Print oNewRange.Text ' gives you My New Text

And I hear that.

I've got scads of loops in there - on tokens, words, sentences,
paragraphs, shapes, textranges - you name it. Rather than ferret all
those out, I'm going to go with the Q&D approach I've now got working.
This thing's due for a client demo on Wed. PM, and I'm really leery of
significant changes at this juncture.

Thanks, though, for listening on a Saturday - true dedication!

I think the root of my problem here is my understanding of a) objects
in general, and b) textranges in particular. It just seems to me that
if I play by the rules, using Replace, InsertBefore, InsertAfter, etc.,
all those changes I made to the original TextRange.text ought to be
reflected in the TextRange.Text when I get done. For a while, I
thought, well, "Maybe it's the dubuuger - he can't keep up with my
changes." But the results I got showed what I've been describing.
Anyway, all's [pretty much] well, it's late and tomorrow's Mother's Day
- so I better get to bed.

'night.
 
D

david.f.jenkins

Good example of what I'm talking about! I think I've just abut milked
all the fun out of this thing that's there to be milked. It's now on
CD and ready for demo. Wish me luck...

Now , if you want some sparetime fun, consider this (posted in another
forum someplace - I forget just where, right now):

I can't compose the VBA that will solve this seemingly simple problem
for me.

In regexspeak, suppose I have this text:

(\S|^) *(->) *(\S|$). I could have, for instance:

->b
a->
a->b
a ->b
a-> b
a -> b
a -> b
..
..
..
well, you get the picture.

I want to replace the "->" with the Wingdings character 170 symbol and
always end up with:

(\S|^) [the wingdings symbol] (\S|$)

Here's the hooker: I want retain the original fonts for group 1 and 2
(or a and b, in my examples above).

This code will replace all the arrows for me just fine, while retaining

the fonts:

sub wingdings(tRange as textrange)

dim foundArrrow as textrange

Set foundArrow = tRange.find(findwhat:="->")
Do While Not (foundArrow Is Nothing)
foundArrow.Characters(1, 2).InsertSymbol fontName:="Wingdings 3",
CharNumber:=170, Unicode:=msoTrue
Set foundArrow = tRange.find(findwhat:="->")
Loop

end sub

But I still have the vexing problem of maintaining the fonts while
trying to surround the Wingdings character with a *one* (no more! no
less!) space.

I've chewed at this thing for a few hours, and always seem to end up
finding a case where the fonts don't end up right.

There's probably an elegantly simple solution, but I sure can't find
it...
 
S

Steve Rindsberg

I
In regexspeak, suppose I have this text:

(\S|^) *(->) *(\S|$). I could have, for instance:

I saw that, but regex one of those "on my list of things to learn" things.

->b
a->
a->b
a ->b
a-> b
a -> b
a -> b
..
..
..
well, you get the picture.

I want to replace the "->" with the Wingdings character 170 symbol and
always end up with:

(\S|^) [the wingdings symbol] (\S|$)

Here's the hooker: I want retain the original fonts for group 1 and 2
(or a and b, in my examples above).

This code will replace all the arrows for me just fine, while retaining

the fonts:

sub wingdings(tRange as textrange)

dim foundArrrow as textrange

Set foundArrow = tRange.find(findwhat:="->")
Do While Not (foundArrow Is Nothing)
foundArrow.Characters(1, 2).InsertSymbol fontName:="Wingdings 3",
CharNumber:=170, Unicode:=msoTrue
Set foundArrow = tRange.find(findwhat:="->")
Loop

end sub

But I still have the vexing problem of maintaining the fonts while
trying to surround the Wingdings character with a *one* (no more! no
less!) space.

I've chewed at this thing for a few hours, and always seem to end up
finding a case where the fonts don't end up right.

There's probably an elegantly simple solution, but I sure can't find
it...
 
D

david.f.jenkins

Steve:

Your life will change (and for the beter, I might add) once you start
using regexes. Once you do, you'll begin missing that functionality in
every text search situation that doesn't offfer it. I just don't see,
for instance, why all of MS Office suite doesn't make that a standard
search method. I've aded a regex search macro button to my standard
toolbars.

Well, I'm off my regex high horse. And I guess we can close this
thread out - thanks for your help.
 
S

Steve Rindsberg

Steve:

Your life will change (and for the beter, I might add) once you start
using regexes.

O man, you scared me. I thought this was another of those religous posts at
first. <g>

I've done enough looking at regular expressions to know how useful they can be,
but w/o support for it that I can count on, I don't like to build anything on
it (most of my stuff has to run on everything from Office 97 onward and
sometimes on Macs too).

Once you do, you'll begin missing that functionality in
 

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