how does a macro know it's reached EOF?

A

Allen_N

I'm trying to use Word for same elementary text processing. I just want to
remove 6 lines from each page (to get rid of page headers in a big report).
My macro works, but it doesn't know when to stop. The macro body is as
follows:

Do
Selection.MoveDown Unit:=wdLine, Count:=6, Extend:=wdExtend
Selection.Delete Unit:=wdCharacter, Count:=1
Selection.MoveDown Unit:=wdLine, Count:=48
Loop Until Selection.Text = ""

(N.B. I set orientation to Landscape and fiddled with margins until all
pages began with the header.)

Several people have asked similar questioins, but everybody that answers
seems to have better methods; no one seems inclined to answer the question:
how does the macro know when the selection has become the end of the document?
 
J

Jay Freedman

Most people who answer questions like this realize that forcing a
macro to behave like it's pressing keys (the "automated typist"
scenario) is the least efficient and most error-prone way of handling
jobs like this. That's why the answer usually involves a different
and, yes, better method.

In this case, the better method would probably be a wildcard search &
replace with a search expression that's crafted to find only the page
headers. Not only would it be easier to program, but it would run
about a hundred times faster, and it wouldn't risk deleting the wrong
lines just because one page is a little different from the others.

But... If you insist on making Word behave like a refugee from the
1980s word-processor scrap heap, you can do it.

Declare a numeric variable and assign to it the return value of the
final MoveDown call. The return value of the call is the number of
lines the Selection actually moved. End the loop when that return
value is less than the requested number of lines, because the
Selection can't move down past the end of the document:

Dim actualMove As Long
Do
Selection.MoveDown Unit:=wdLine, Count:=6, Extend:=wdExtend
Selection.Delete Unit:=wdCharacter, Count:=1
actualMove = Selection.MoveDown (Unit:=wdLine, Count:=48)
Loop Until actualMove < 48

If you're unlucky, this method might still err on the last page if it
contains just the wrong number of lines, so an On Error trap is
recommended.

--
Regards,
Jay Freedman
Microsoft Word MVP
Email cannot be acknowledged; please post all follow-ups to the
newsgroup so all may benefit.
 
J

Jezebel

Probably no-one wanted to volunteer because it's just such a silly way to
process a document, for any number of reasons. But if you must --

Selection.start = Activedocument.range.end - 1
 
A

Allen_N

Thanks for the advice.

Silly? No sillier than fixed-format, mainframe-generated, ASCII reports,
surely. I though I was being clever by using Word to process such a text file
rather than writing a VB program to do so.

If the source data had been a DOC file I would certainly have been inclined
to think in terms of the Word object model. Speaking for myself, however, BFI
sequential processing is easier to implement when I am unfamiliar with object
model and disinclined to spend hours wading through Help screens.

Cheers!
 
J

Jezebel

There are much easier ways to process a text file with VBA than that. For
one:

1. Read the file directly into an array --

Dim pLines() as string
Dim pFileNum as long
Dim pIndex as long

pFileNum = FREEFILE
Open "c:\.....\myfile.txt" for input as pFileNum
pLines = split(input(LOF(#pFileNum,pFileNum)), vbCr)
Close pFileNum

2. Process the lines --
For pIndex = lbound(pLines) to ubound(plines)
... do whatever with pLines(pIndex)
Next
 
A

Allen_N

Cool! I'll have to have a go at that.

-- Allen

Jezebel said:
There are much easier ways to process a text file with VBA than that. For
one:

1. Read the file directly into an array --

Dim pLines() as string
Dim pFileNum as long
Dim pIndex as long

pFileNum = FREEFILE
Open "c:\.....\myfile.txt" for input as pFileNum
pLines = split(input(LOF(#pFileNum,pFileNum)), vbCr)
Close pFileNum

2. Process the lines --
For pIndex = lbound(pLines) to ubound(plines)
... do whatever with pLines(pIndex)
Next
 
L

Lüko Willms

Am Mon, 6 Nov 2006 03:17:01 UTC, schrieb Allen N
Silly? No sillier than fixed-format, mainframe-generated, ASCII reports,
surely. I though I was being clever by using Word to process such a text file
rather than writing a VB program to do so.

Alternatively to reading all the document into an array (one entry
per line), you could avoid using MS-Word altogether and write a script
reading the mainframe outpout as a text stream object, and copying it
to a new text stream; scanning each line for the characteristics of
the page break and headers, and dropping those lines from the copy
process, or skipping the fixed number of lines from the source file
with the SkipLine method.

something like this (untested and uncompiled) script in VBScript:


Dim fso, inFile, outFile, myLine
const nameInFile = "C:\tmp\mainframe_original.txt") ' example
const nameOutFile = "C:\tmp\mainframe_edited.txt") ' another
example
const pageMarker = "String which marks the begin of the m/f page
break"

set fso = CreateObject("Scripting.FileSystemObject")
set inFile = fso_OpenTextFile(nameInfile, ForReading, TriStateFalse)
' false : read as ASCII
set outFile = fso.CreateTextFile(nameOutFile, ForWriting,
TriStateFalse)
myLine = inFile.ReadLine
Do While NOT inFile.AtEndOfStream
IF InStr(myLine, pageMarker) = 0 ' alternatively use the RegExp
object
outFile.WriteLine(myLine)
Else
For i = 1 to 5
inFile.SkipLine
Next
End If
myLine = inFile.ReadLine
Loop
inFile.Close
outFile.Close

'############### end of script ###############

One could make it into a SUB and pass the filenames as parameters,
or better pass them on the commandline, and processing the commandline
parameters as the WshArguments object.

Some error handling should also be added for missing parameters,
non-existing files, writing or reading errors, etc.


Yours,
L.W.
 
G

Greg Maxey

Jezebel,

I tried running your example on a simple text file and I get a compile
error on the "#" in this line:

pLines = split(input(LOF(#pFileNum,pFileNum)), vbCr) 'Compile error on
"#"

I haven't messed with this sort of code very much but found that I
could get a msgbox to display the text of the file using:

MsgBox Input(LOF(pFileNum), pFileNum) 'Returns the text. No error

However is I declare a string and use:
pStr = Input(LOF(pFileNum), pFileNum) 'Run-Time error 62 "Input past
end of file"

I get a runtime error 62 "Input past end of file"

Can you explain what I am doing wrong? Can you explain why the msgbox
text can be created but not a string?

Thanks.
 
G

Greg Maxey

I got this to work:

Sub Test()
Dim pLines() As String
Dim pFileNum As Long
Dim pIndex As Long
pFileNum = FreeFile
Open "c:\Txt file.txt" For Input As pFileNum
pLines = Split(Input(LOF(pFileNum), pFileNum), vbCr)
Close pFileNum
For pIndex = LBound(pLines) To UBound(pLines) - 1
MsgBox pLines(pIndex)
Next
End Sub
 
J

Jezebel

sorry about the typos.



Greg Maxey said:
I got this to work:

Sub Test()
Dim pLines() As String
Dim pFileNum As Long
Dim pIndex As Long
pFileNum = FreeFile
Open "c:\Txt file.txt" For Input As pFileNum
pLines = Split(Input(LOF(pFileNum), pFileNum), vbCr)
Close pFileNum
For pIndex = LBound(pLines) To UBound(pLines) - 1
MsgBox pLines(pIndex)
Next
End Sub
 
A

Allen_N

Thanks, Lüko.

I've never used VBScript, but I was originally going to do something like
that with VB4. I thought I'd try Word in case I later wanted to generalise
the macro for wider application.
 
C

conradrg

Here's the code you should use, and I tested it to see if it works.
simply added the end of document statement to what you previousl
wrote.

Do
Selection.MoveDown Unit:=wdLine, Count:=6, Extend:=wdExtend
Selection.Delete Unit:=wdCharacter, Count:=1
Selection.MoveDown Unit:=wdLine, Count:=48
Loop Until Until ActiveDocument.Range.End - 1

OR

Do Until Until ActiveDocument.Range.End - 1
Selection.MoveDown Unit:=wdLine, Count:=6, Extend:=wdExtend
Selection.Delete Unit:=wdCharacter, Count:=1
Selection.MoveDown Unit:=wdLine, Count:=48
Loop

Conrad R. G
 
Top