T'other day, I knocked together a macro, for a friend, to number the paragraphs in a Microsoft Word document ("manual" rather than hard-coded numbering, that is):
Sub NumberingParagraphs() Dim iParagraphs As Integer iParagraphs = ActiveDocument.Paragraphs.Count Selection.HomeKey unit:=wdStory Do While iCount < iParagraphs iCount = iCount + 1 Selection.TypeText iCount & ": " Selection.MoveDown unit:=wdParagraph Loop End Sub
My mate, being curious about, but not having experience of, the workings of such things, took a look and got the basic idea, but couldn't get his head around why the number of loops is seemingly instructed to be one less than the number of paragraphs. Surely, he said, it should be "less than or equal to," rather than "less than." Well, no. His kid got it straight away, and came up with a lovely semi-analogy; which I now share, in hopes that others who've been puzzled by this oft-seen seeming-paradox might see the light. Let's literally (yet figuratively) walk through the macro…
You're in a room, in front of a computer. On the screen is a document. You count the paragraphs. (That's the meaning of the first two lines of the above Sub.) There are three.
You click the cursor to the very start of the document. (That's the line about the home key.)
Noting that the front door of the room cannot be opened from the inside (and that there's a man stood just inside it, but he's not important yet), you exit through the back door and walk around the outside to the front. (This stroll is necessary for narrative, not analogical, reasons. We need to get you to the front door.)
There's a lady stood by the front door. She asks you how many paragraphs there are in the document. She then tells you that after she's seen you enter the door twice, she'll stop you entering again. (That's the "Do while less than the number of paragraphs" line.) At present she's seen you use the door zero times.
You enter. The chap inside the door tells you that "iCount" is the number of times he has seen you enter. Which is once. (That's the "iCount…" line.)
At the computer, you leave the cursor where it is and type your iCount number: "1:_." (The "TypeText" line.) Then you move the cursor to the start of the next paragraph. (The "MoveDown" line.)
Now you "loop" by going out the back and around to the front (this time for analogical reasons). The lady tells you that she's seen you enter one time. You go in. "Two," says the man, so you type "2:_," move the cursor down a paragraph, and go around again. "Two times," says the woman. "Three," says the bloke. You type "3:_," try to move to the next paragraph, but can't 'cause it don't exist, and go out of the back door and around to the front again… "Bugger off!" says the lady, going into full-on rough-nightclub bouncer mode. "You're done!"
And you are done. What's happened is that the first line of the loop ("Do while…") has counted the same number of times as the second, but the first started at nought while the second started at one (Count your fingers starting at "nought" on the thumb, and you'll still speak out five digits (Oh, I'm so punny!), but you'll only reach "four."), and it's the first line's count that limits your turns through the loop. Or, in terms of our analogy of a literal walk-through, the woman has counted your use of the door on three occasions (nought one two) and so has the man (one two three); and it's her count that determines the number of times you go through the loop, while his decides what you type.
And that's me lot, except that the finished product is a little different from the version I posted above. I simplified it so as to avoid side-tracks and complications. The actual macro, shown below, will number all paragraphs in the document if no text is selected, or if some is selected, will number only those paragraphs containing selected text. (It's written so you don't need to select complete paragraphs.)
—Daz
Sub NumberingParagraphs2() Dim iParagraphs As Integer If Selection.Type = wdSelectionIP Then iParagraphs = ActiveDocument.Paragraphs.Count Selection.HomeKey Unit:=wdStory Else iParagraphs = Selection.Paragraphs.Count Selection.StartOf Unit:=wdParagraph End If Do While iCount < iParagraphs iCount = iCount + 1 Selection.TypeText iCount & ": " Selection.MoveDown Unit:=wdParagraph Loop End Sub
You may use these HTML tags in comments<a href="" title=""></a> <abbr title=""></abbr>
<acronym title=""></acronym> <blockquote></blockquote> <del></del>* <strike></strike>† <em></em>* <i></i>† <strong></strong>* <b></b>†* is generally preferred over †
Why not a “For” loop? I’ve been in the computer industry several decades, and practically every time I see a loop someone else has written, I see it has been programmed as a “while”. Not only does this commit the user to keeping track of the index variable and increment it as appropriate, but it also means that the scope of that index variable is outside the loop itself.
While it’s not “wrong” as such to use a while loop, it is considered better style to use “for” when you know exactly how many times to loop (in this case the number of paragraphs, already given).
Also, as I say while it’s not “wrong” as such, it does leave room for mistakes to creep in. I have found a lot over the last (harrumph) years that the most common bugs are those caused by the programmer cocking up his indices in a while loop. One cropped up the other week.
Just sayin’. I’m not familiar enough with Word (I’m not a big fan, I use LaTeX) to know whether it supports a For / Next loop. If it doesn’t, feel free to kick me round the metaphorical server room.
Well, mostly ’cause I’m still learning, and I tend to use methods I know until forced to use others. Still an’ all, how’s this?
Prob’ly saves a good few milliseconds! 🙂
FYI for anyone who is interested:
The If – Then – Else part basically says “If no text is selected, count all the paragraphs in the document then move the cursor to the very start of the doc. Otherwise (i.e. if some text is selected) count the number of paragraphs selected (or partially selected), then move the cursor to the beginning of the first paragraph containing selected text.”
Bloody hell Daz, that takes me back. I remember FOR NEXT loops, IF THEN ELSE, GOTO, GOSUB etc from when we did BASIC programming at school in’t early 1980s. We had a BBC Micro and a cassette player for a hard drive!
I had no idea that modern programs still used a kind of BASIC nowadays. You might have just renewed my interest in coding. Ta.
Nevermind. Just had a look at Visual Basic – it’s all indents and nested whatsits. I preferred the proper way of doing it…
10 REM blah blah blah
20 PRINT “Type in a number”
30 IF n=73095709342570325 THEN PRINT “Correct” ELSE GOTO 20
40 END
Or something like that. It was so much easier then – why do they have to make it more difficult.
The indents aren’t actually necessary. They just make it easier to see what’s nested within what, just like in HTML.
If you take a look at the examples given on The Fount Of All Knowledge™ the evolution of the various generations of BASIC is ackshully fairly gradual.
Just had a look at them examples – especially the one headed ‘The following example is in Visual Basic .NET:’.
I’m impressed, or I would be if I had any idea what any of it means. I think I’ll skip coding.
Nice one. Processing time saved is not as important here as clarity of code intent.
this code saves my time 😀 I’m new in this language