const blank = ' '; type pac80 = packed array [1..80] of char; {---------------------------------------------------} function trim ( buf : pac80; var f_width : integer) : pac80; {trim takes the 80-byte array passed and physically trims } {the leading blanks off (by left-shifting the text), and } {logically trims any trailing blanks. The resulting width} {is returned in "f_width". } { } {Example: trim (' cat ', W); } { returns: 'cat ', and W = 3 } { } {Note: in left-shifting, the "new" characters at the end } {of the buffer will be blanks. } const max_inx = sizeof (buf); var first_inx: integer; {index of first non-blank in buf} last_inx : integer; {index of last non-blank in buf} inx : integer; {used to index in buf/new_buf} new_buf : pac80; {will hold left-shifted text} width : integer; {length of "trimmed" text} begin {Find first non-blank character in buf...} first_inx := 1; while (first_inx <= max_inx) and (buf [first_inx] = blank) do first_inx := first_inx + 1; {Continue only if we found a non-blank.. .} {Note that if the first non-blank is the } {first character, then we don't need to } {"shift" the text, so we can do a high- } {speed copying of the data in buf to trim's } {functional result. } if first_inx > max_inx then begin {buf is entirely blank} trim := ' '; {pass back a blank buffer} width := 0; {0 -> no non-blank text!} end else begin {must copy data to new_buf} {First, determine width...} {Note that we can avoid a complex while} {condition because we know that we'll } {find a non-blank before last_inx hits 0. } last_inx := max_inx; while buf [last_inx] = ' ' do last_inx := last_inx - 1; width := (last_inx - first_inx) + 1; {Copy the data to new_buf...} {Note that since the "for" below might not} {copy max_inx chars, we need to make sure } {that the trailing part of new_buf is } {blanked out ... to be nice to the caller.} {This could be omitted if the definition } {of "trim" made it clear that the trailing} {data should be undefined. } {(See commentary for alternative) } if width < max_inx then new_buf := ' '; {blank out entire new_buf} for inx := 1 to width do new_buf [inx] := buf [inx + (first_inx - 1)]; trim := new_buf; end; f_width := width; {tell caller the width} end {trim proc};Notes:
NEW_BUF
array
is less than the cost of an additional FOR
loop to blank out the tail end. This becomes less likely
to be true as (a) new_buf gets bigger; (b) the probability of
a large number of leading/trailing blanks decreases; and (c) the
quality of compiler optimization increases.
On the other hand,
the *human* time to understand the
new_buf := ' '
is significantly less than
to understand an additional FOR
loop. Remember to ask:
will it take more time
to write faster code than will ever
be saved by that new code?
Still, here's the FOR
loop code...replace the
"new_buf := ' ';
" with:
{Blank out tail end} for inx := width + 1 to max_inx do new_buf [inx] := ' ';
<PAC> := ' '
to blank an entire PAC variable, then the trim := ' '
can be replaced easily (exercise for the reader).
width
, instead of the
f_width
parameter for efficiency. Since
f_width
is a call-by-reference, every use of it would
require a memory access. width
, being a local
variable, is more likely to be promoted to a register by
a compiler (and is therefore likely to be faster).
In general, I avoid accessing simple by-reference parameters via this technique.
(Click here to go back to the commented bad version.)
(Click here to go back to the uncommented
bad version.)
(Click here for the "How To Code Pascal" paper.)