(Hello, Reddit.com visitors!)
Be sure to check out part 1, part 2, part 3 and part 4.
Behold, the new champion of BASIC word wrap routines! Darren Atkinson sends in this two line wrap routine which makes use of the INSTR() function to find spaces in a string. It uses more integer variables, but does not use any strings. And, it’s FAST! It parses the test cases with a count of around 60 — half the time of the previous fast version! Size-wise, it clocks in at 231 bytes, which is five bytes smaller than his previous version. Jim Gerrie’s still has the edge in the size category, but to get this much more speed for just a few bytes more might be a worthy tradeoff.
Darren does note:
I’m not sure the speed increase will be as dramatic when printing strings with average length words.
– Darren
I believe this is because his routine zips through long lines immediately, but would spend more time searching for spaces in a normal sentence. I will do some benchmarks using normal sentences to see how it stacks up.
Here is the full version:
0 GOTO100 1 ST=1:LN=LEN(A$)+1:FORPP=1TOLN:LW=INSTR(PP,A$," "):IFLW THENIFLW-ST<WD THENPP=LW:NEXTELSEELSEPRINTMID$(A$,ST):RETURN 2 IFLW-ST=WD THENPRINTMID$(A$,ST,LW-ST);:PP=LW:ST=LW+1:NEXTELSEIFPP<>ST THENPRINTMID$(A$,ST,PP-ST-1):ST=PP:PP=PP-1:NEXTELSEPRINTMID$(A$,ST,LW-ST)" ";:PP=LW:ST=LW+1:NEXT 100 CLS 110 INPUT"SCREEN WIDTH [32]";WD 120 IF WD=0 THEN WD=32 130 INPUT"UPPERCASE ([0]=NO, 1=YES)";UC 140 TIMER=0:TM=TIMER 150 PRINT "SHORT STRING:" 160 A$="THIS SHOULD NOT NEED TO WRAP.":GOSUB 1 170 PRINT "LONG STRING:" 180 A$="This is a string we want to word wrap. I wonder if I can make something that will wrap like I think it should?":GOSUB 1 190 PRINT "WORD > WIDTH:" 200 A$="123456789012345678901234567890123 THAT WAS TOO LONG TO FIT BUT THIS IS EVEN LONGER ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234 SO THERE.":GOSUB 1 210 PRINT"TIME TAKEN:"TIMER-TM 220 END
Hi approach uses a FOR/NEXT loop to scan through each character position. By doing an INSTR(A$,PP,” “) (PP being the position 1-length), he checks to see if that position would be past the end of the line and, if not, he updates the PP position so it continues from there. This lets the assembly BASIC routine rapidly scan for the spaces instead of the BASIC interpreter doing it one byte a at a time. Very clever!
Great job, Darren!
His routine gave me another idea, and I will be providing an updated test program to try a few other things and see how we all stack up.
Until then…
Good work. I hadn’t quite gotten the logic right in a BASIC09 version that would use SUBSTR(), its equivalent of INSTR().
Of course, the real problem is that neither of them have an equivalent of strrchr(), because what you’re after is the *last* occurrence of space in the string to be output:
#include “stdio.h”
#include “string.h”
void wrap(const char *s, int width)
{
int len = strlen(s);
while (len > width) {
const char *s1 = strrchr(s, ‘ ‘);
if (s1 == NULL || s1 – s > width + 1) {
fwrite(s, 1, width, stdout);
s += width;
len -= width;
} else if (s1 – s == width + 1) {
fwrite(s, 1, s1 – s – 1, stdout);
len -= s1 – s;
s = s1 + 1;
} else {
fwrite(s, 1, s1 – s, stdout);
len -= s1 – s;
s = s1 + 1;
}
putchar(‘\n’);
}
if (len > 0) {
fwrite(s, 1, len, stdout);
putchar(‘\n’);
}
}
Apologies if indentation or greater than or less than is corrupted; just in case, I put the files to be #included in quotes.
Using INSTR/SUBSTR/strchr(), you can go looking for the last space that is no more than width characters from the start (or width + 1, in which case you have to take care not to print that last space). Unfortunately, in BASIC or BASIC09 you have to keep taking RIGHT$() to skip the spaces you’ve already found, and that may well use up string space.
Of course the above code is wrong. You want the last space that’s no more than width characters from the start of what remains to be printed, so you’d be calling strrchr repeatedly too, so you might as well start from the front.
I’ll see about doing it up in BASIC09.
Reverse could at least start at Start Position + Width and search back. I toyed with an alternate version using INSTR() but didn’t get it working yet.