 |
SAS Helpful Hints
Proc Tabulate
Proc tabulate is a very useful procedure, but personally, I do not
like the line breaks SAS puts between the data elements. Our solution
was to write a program that would read SAS tabulate output, and insert
nice line and page breaks. Our tabulate conversion program can be
cut and paste from this web page.
Change This:

Into This!
Usage Example:
%include '/Library/TabulateLib.sas';
%CleanTable(table.lst,newtable.lst);
TabulateLib.sas:
/*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}
Biostat Tabulate Format Conversion Version 2.0
This set of macros inserts nice line and page
breaks into a
Proc Tabulate with NOSEPS and ps=32767(max)
Arthur Watts 6/5/2002
{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*}{*/
%Macro CleanTable(file1,file2);
Filename ina "&file1"; *old file name;
Filename outa "&file2"; *new file name;
*Windows: Max lines per page=46 for font=9, 51 for
font=8;
*Solaris: Max lines per page=58;
%Let maxlines=51;
%Let windows=;
%Let solaris=|---+-|;
%Let specialchars=&windows;
Data work.mdevice;
If Index(Sysget('path'),'\')>0 Then Do;
Call Symput('specialchars','');
Call Symput('maxlines','51');
End; Else Do;
Call Symput('specialchars','|---+-|');
Call Symput('maxlines','58');
End;
Run;
*Find proper indents and save them in macro variables;
Data work.mAA;
Infile ina N=1 Missover Delimiter='~' End=eof;
Length aline $ 200 ztitle $ 200;
linenum=0; *Line number;
Input aline;
Do While (Substr(Left(aline),1,2)^=Substr("&specialchars",1,2));
*Save title/header lines;
linenum=linenum+1;
/*If line ends with
a page number or date, right justify, otherwise center;*/
If Length(aline)>=10
Then Do;
If
Substr(aline,Length(aline)-1,2)=' 1' and Substr(aline,Length(aline)-9,1)=','
Then Do;
*Found
page number and date on same line;
ztitle=Trim(Left(Substr(aline,1,Length(aline)-39)));
indent=Length(aline)-Length(ztitle)+1;
width=indent+Length(aline);
End;
Else
If Substr(aline,Length(aline)-1,2)=' 1' and Substr(aline,Length(aline)-9,1)^=','
Then Do;
*Found
page number without date on same line;
ztitle=Trim(Left(Substr(aline,1,Length(aline)-1)));
indent=Length(aline)-Length(ztitle)+1;
width=indent+Length(aline);
End;
Else
If Substr(aline,Length(aline)-5,1)=',' Then Do;
*Found
a date without page number(not line 1);
If
Length(aline)>=35 Then Do; *Has title;
ztitle=Trim(Left(Substr(aline,1,Length(aline)-35)));
indent=Length(aline)-Length(ztitle);
End;
Else indent=width-Length(aline); *No title;
End;
Else
indent=Int((width-Length(aline))/2.0);
End;
Select (linenum);
When
(1) Call Symput('indnt1',indent);
When
(2) Call Symput('indnt2',indent);
When
(3) Call Symput('indnt3',indent);
When
(4) Call Symput('indnt4',indent);
When
(5) Call Symput('indnt5',indent);
When
(6) Call Symput('indnt6',indent);
When
(7) Call Symput('indnt7',indent);
When
(8) Call Symput('indnt8',indent);
When
(9) Call Symput('indnt9',indent);
When
(10) Call Symput('indnt10',indent);
When
(11) Call Symput('indnt11',indent);
When
(12) Call Symput('indnt12',indent);
When
(13) Call Symput('indnt13',indent);
When
(14) Call Symput('indnt14',indent);
When
(15) Call Symput('indnt15',indent);
When
(16) Call Symput('indnt16',indent);
When
(17) Call Symput('indnt17',indent);
When
(18) Call Symput('indnt18',indent);
When
(19) Call Symput('indnt19',indent);
When
(20) Call Symput('indnt20',indent);
End;
Call Symput('indnt',indent);
Input aline;
End;
Stop;
Run;
*Create a new tabulate output!;
Data work.mAB;
Infile ina N=1 Missover Delimiter='~' End=eof;
File outa;
Array titles{20} $200;
Array bys{8} $ 50;
Length aline $ 200 break $ 200 break2 $ 200
bottom $ 200 top $ 200 spaces $ 60 ztitle $ 200;
titlnum=0; *Number of title/header lines;
bynum=0; *Number of by lines;
maxbynum=1; *Longest list of by lines;
newby=0; *Start new by list;
count=0; *Should we count by lines?;
linenum=0; *Line number;
depth=99; *Indent to label inside table;
blocksize=0; *Number of lines between breaks;
bs=0; *Temp/growing blocksize;
pagenum=1; *Page number;
newpage=0; *New page flag, to reset by variables;
spaces=' ';
Input aline;
Do While (Substr(Left(aline),1,2)^=Substr("&specialchars",1,2));
*Save title/header
lines;
linenum=linenum+1;
/*If line ends with
a page number or date, right justify, otherwise center;*/
If Length(aline)>=10
Then Do;
If
Substr(aline,Length(aline)-1,2)=' 1' and Substr(aline,Length(aline)-9,1)=','
Then Do;
*Found
page number and date on same line;
ztitle=Trim(Left(Substr(aline,1,Length(aline)-39)));
indent=Length(aline)-Length(ztitle)+1;
width=indent+Length(aline);
aline=Substr(aline,1,Length(aline)-4);
top=Trim(aline)||'
'||Compress(pagenum);
titleindent=5;
*Space between date and page number;
End;
Else
If Substr(aline,Length(aline)-1,2)=' 1' and Substr(aline,Length(aline)-9,1)^=','
Then Do;
*Found
page number without date on same line;
ztitle=Trim(Left(Substr(aline,1,Length(aline)-1)));
indent=Length(aline)-Length(ztitle)+1;
width=indent+Length(aline);
aline=Substr(aline,1,Length(aline)-4);
top=Trim(aline)||Substr(spaces,1,indent-2)||Compress(pagenum);
titleindent=indent;
*Space between title and page number;
End;
Else
If Substr(aline,Length(aline)-5,1)=',' Then Do;
*Found
a date without page number(not line 1);
If
Length(aline)>=35 Then Do; *Has title;
ztitle=Trim(Left(Substr(aline,1,Length(aline)-35)));
indent=Length(aline)-Length(ztitle);
End;
Else indent=width-Length(aline); *No title;
End;
Else
indent=width-Int(Length(aline)/2.0);
End;
titlnum=titlnum+1;
titles{titlnum}=aline;
Select (linenum);
When
(1) Put @&indnt1 top $;
When
(2) Put @&indnt2 aline $;
When
(3) Put @&indnt3 aline $;
When
(4) Put @&indnt4 aline $;
When
(5) Put @&indnt5 aline $;
When
(6) Put @&indnt6 aline $;
When
(7) Put @&indnt7 aline $;
When
(8) Put @&indnt8 aline $;
When
(9) Put @&indnt9 aline $;
When
(10) Put @&indnt10 aline $;
When
(11) Put @&indnt11 aline $;
When
(12) Put @&indnt12 aline $;
When
(13) Put @&indnt13 aline $;
When
(14) Put @&indnt14 aline $;
When
(15) Put @&indnt15 aline $;
When
(16) Put @&indnt16 aline $;
When
(17) Put @&indnt17 aline $;
When
(18) Put @&indnt18 aline $;
When
(19) Put @&indnt19 aline $;
When
(20) Put @&indnt20 aline $;
End;
Input aline;
End;
break=aline; *Primary break between blocks;
*Bottom of table/page:;
bottom=Substr("&specialchars",3,1)||Substr(break,2,Length(break)-2)||Substr("&specialchars",4,1);
plus=Index(bottom,Substr("&specialchars",5,1));
Do While (plus>0); *Replace + with inverted
Ts;
bottom=Substr(bottom,1,plus-1)||Substr("&specialchars",6,1)||Substr(bottom,plus+1,Length(bottom)-plus);
plus=Index(bottom,Substr("&specialchars",5,1));
End;
linenum=linenum+1;
Do Until (eof);
Input aline;
* Skip any page breaks;
If (Substr(aline,1,1)=Substr("&specialchars",3,1)
And Not(eof)) Then Do;
Do
Until (Substr(Left(aline),1,2)=Substr("&specialchars",1,2)
or eof);
Input
aline;
End;
Input
aline;
End;
*Check depth or indent
inside table;
l=Length(aline);
l2=Length(Left(Substr(aline,2,l-1)));
newdepth=l-l2-1;
If newdepth<depth
Then Do; count=1; cutdepth=newdepth; End;
If newdepth>depth
Then count=0;
If newdepth<depth
Or (0<bynum<=maxbynum and newdepth=depth) Or (0<bynum<maxbynum)
Then Do;
*Save
by variables, may be several lines;
If
newdepth<depth Then Do; *New by items found;
bynum=0;
If newdepth>0 Then newby=0;
End;
If
newdepth=0 Then newby=1; *New by list found;
bynum=bynum+1;
If
(newdepth^=depth and bynum>maxbynum) Then newby=0; *Completed saving
by lines;
Else
Do;
rtsend=1+Index(Substr(aline,2,Length(aline)-1),Substr("&specialchars",7,1));
If
rtsend>1 Then Do; *Not EOF;
If
cutdepth=0 or newby>0 Then bys{bynum}=Substr(aline,2,rtsend-2);
Else
bys{bynum}=Substr(bys{bynum},1,cutdepth)||Substr(aline,cutdepth+2,rtsend-cutdepth+1);
If
count>0 Then maxbynum=max(maxbynum,bynum);
End;
End;
End; Else Do; bynum=0;
newby=0; End;
If newdepth<depth
Then Do; *End of block, insert a break;
blocksize=Max(blocksize,bs);
bs=0;
If
linenum+blocksize+1<&maxlines Then Do; *Not a new page;
linenum=linenum+1;
If
newdepth>0 Then Do; *Insert a break, Update by variables;
*Insert
by variables if this is the beginning of a new page;
If
1<=newpage<=maxbynum Then Do;
If
newdepth>0 Then
break2=Substr("&specialchars",7,1)||Substr(bys{newpage},1,newdepth)||Substr(break,newdepth+2,l2);
newpage=newpage+1;
If
newpage>maxbynum Then newpage=0;
End;
Else break2=Substr("&specialchars",7,1)||Substr(spaces,1,newdepth)||Substr(break,newdepth+2,l2);
Put
@&indnt break2 $;
End;
Else
If rtsend>1 Then Put @&indnt break $; *If not EOF;
End;
Else
If Not(eof) Then Do; *New Page;
newpage=1;
Put
@&indnt bottom $;
Put
'' @; *Page Break;
pagenum=pagenum+1;
top=Trim(titles{1})||Substr(spaces,1,titleindent-4)||'
'||Compress(pagenum);
If
pagenum>9 Then top=Trim(titles{1})||Substr(spaces,1,titleindent-4)||'
'||Compress(pagenum);
If
pagenum>99 Then top=Trim(titles{1})||Substr(spaces,1,titleindent-4)||Compress(pagenum);
If
pagenum>999 Then top=Trim(titles{1})||Compress(pagenum);
Put
@&indnt1 top $;
Do
i=2 To titlnum;
Select
(i);
When
(2) Put @&indnt2 titles{i} $;
When
(3) Put @&indnt3 titles{i} $;
When
(4) Put @&indnt4 titles{i} $;
When
(5) Put @&indnt5 titles{i} $;
When
(6) Put @&indnt6 titles{i} $;
When
(7) Put @&indnt7 titles{i} $;
When
(8) Put @&indnt8 titles{i} $;
When
(9) Put @&indnt9 titles{i} $;
When
(10) Put @&indnt10 titles{i} $;
When
(11) Put @&indnt11 titles{i} $;
When
(12) Put @&indnt12 titles{i} $;
When
(13) Put @&indnt13 titles{i} $;
When
(14) Put @&indnt14 titles{i} $;
When
(15) Put @&indnt15 titles{i} $;
When
(16) Put @&indnt16 titles{i} $;
When
(17) Put @&indnt17 titles{i} $;
When
(18) Put @&indnt18 titles{i} $;
When
(19) Put @&indnt19 titles{i} $;
When
(20) Put @&indnt20 titles{i} $;
End;
End;
linenum=titlnum+1;
Put
@&indnt break $;
End;
End;
*Insert by variables
if this is the beginning of a new page;
If 1<=newpage<=maxbynum
Then Do;
If
newdepth>0 Then
aline=Substr("&specialchars",7,1)||Substr(bys{newpage},1,newdepth-1)||Substr(aline,newdepth+1,l2+1);
newpage=newpage+1;
If
newpage>maxbynum Then newpage=0;
End;
linenum=linenum+1;
bs=bs+1;
depth=l-1-l2;
Put @&indnt aline
$;
End;
Run;
Proc Datasets Library=work Memtype=data;
Delete mdevice mAA mAB;
Run;
%Mend CleanTable;
%Macro indentdef;
%Do i=1 %To 20;
%Global indnt&i;
%Let indnt&i=1;
%End;
%Mend indentdef;
%indentdef;
Please send your comments and suggestions about this web page to A. Watts
(watts@bst.rochester.edu)
|