|
|
|
|
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:
- I'm assuming that, on average, the cost of blanking the entire
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] := ' ';
- Note that if your compiler doesn't support:
<PAC> := ' '
to blank an entire PAC variable, then the trim := ' ' can be
replaced easily (exercise for the reader).
- We also avoided using any predefined functions, to preseve the comparison
of coding style/methods.
- I used a local variable,
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.)
(Updated 2000-05-04)
|
|
|
|