Image483_fmt.png

Chapter 15 Miscellaneous Topics

15.1 A Few Miscellaneous Tips

15.1.1 Customizing Your NOTEs, WARNINGs, and ERRORs

15.1.2 Enhancing Titles and Footnotes with the #BYVAL and #BYVAR Options

15.1.3 Executing OS Commands

15.2 Creating User-defined Functions Using PROC FCMP

15.2.1 Building Your Own Functions

15.2.2 Storing and Accessing Your Functions

15.2.3 Interaction with the Macro Language

15.2.4 Viewing Function Definitions

15.2.5 Removing Functions

15.3 Reading RTF as Data

15.3.1 RTF Diagram Completion

15.3.2 Template Preparation

15.3.3 RTF as Data

As if everything in this book was not eclectic enough to be an entire book of miscellaneous topics, the final chapter is the miscellaneous chapter of this eclectically miscellaneous book.

15.1 A Few Miscellaneous Tips

Here are just a few of many tips.

SEE ALSO

If you want more tips read the ‘Tip of the Day’ on sasCommunity.org. You can even have the tip tweeted to you.

15.1.1 Customizing Your NOTEs, WARNINGs, and ERRORs

The PUT, PUTLOG, and %PUT statements can be used to generate customized notes, warnings, and errors in the LOG. Since these statements are executable, logic can be used to conditionally execute them. The text written to the LOG follows the systems conventions when the statement keyword is immediately followed by one of the following:

  • NOTE:

The note is written in blue.

  • WARNING:

Warnings are written in green.

  • ERROR:

Errors are written in red and are summarized along with other errors.

The keyword must be capitalized and must be immediately followed by a colon.

lock sashelp.class;
%put NOTE: class should be locked;
41   lock sashelp.class;
NOTE: SASHELP.CLASS.DATA is now locked for exclusive access by you.
42   %put NOTE: class should be locked;
NOTE: class should be locked

You can also follow the words NOTE, WARNING, or ERROR with a dash instead of a colon. The customized message will still appear in the LOG with the appropriate color; however, the word NOTE, WARNING, or ERROR will not appear.

SEE ALSO

Don Henderson wrote a tip on sasCommunity.org that discusses this topic http://www.sascommunity.org/wiki/Tips:Using_NOTE,_WARNING,_ERROR_in_Your_Program%27s_Generated_Messages.

15.1.2 Enhancing Titles and Footnotes with the #BYVAL and #BYVAR Options

When your PROC step uses a BY statement the values of the BY variables or even the variable names themselves can be inserted into the title or footnote. Although available for use in a few other locations, the #BYVAL, #BYVAR, and #BYLINE options were designed to be used in the TITLE and FOOTNOTE statements.

The #BYVAR option is used to place the variable name in the title while the #BYVAL option is used to place the value of that BY variable. Both the #BYVAL and #BYVAR options have two ways of addressing a specific BY variable from the list of BY variables. These two forms (implicit and explicit) can be used interchangeably. Implicit naming uses a number that corresponds to the list of BY variables (left to right): #BYVAR1 and #BYVAL1 would both refer to the first variable in the list of variables. Explicit naming uses the variable name in parentheses. The variable must be on the BY list: #BYVAR(RACE) and #BYVAL(RACE). Only a single variable may be used within the parentheses.

Here the #BYVAR and #BYVAL options are used to identify the RACE in a PROC FREQ step.

options nobyline; Callout 1
title2 'Summary for #byvar1 #byval1'; Callout 2
proc freq data=demog;
   by race;
   table sex;
   run;

Callout 1 Since the BY variable information will appear in the title the procedure’s BY line is not needed.

image shown here

Callout 2 Both the #BYVAR and #BYVAL options are used and the variables are selected implicitly. Notice that these options may be used inside of either single or double quotes.

The same title statement could have been written using these options with explicit specifications.

title2 'Summary for #byvar(race) #byval(race)';

These options work well with the macro language, but make sure that, unlike the titles above, you use double quotes so that the macro language elements will be resolved correctly.

In the PROC FREQ shown above the procedure automatically creates a separate page for each combination of the BY variables. This ensures that the titles and the BY variable values for any given page will be synchronized. Some procedures do not necessarily generate a separate page for each BY group, when this is the case the titles and the actual BY variable values may appear to be incorrect.


				
title2 'BY Information #byline'; Callout 3
proc print data=demog;
   by race sex;
   var lname fname dob;
   run;
15.1.2 BY Values in Titles
BY Information race=2 patient sex=F Callout 4
race=1 patient sex=M Callout 5
(continued)
Obs    lname        fname         dob
 42    Thomas       Daniel    23MAY38
 43    Uno          Robert    21MAR44
race=2 patient sex=F Callout 6
Obs     lname     fname         dob
 44    Adams      Mary      12AUG51
 45    Adamson    Joan            .
 46    Batell     Mary      12JAN37
. . . . portions of the report not shown . . .

PROC PRINT will only generate a new page for each BY group when the PAGEBY statement is used. Without the PAGEBY statement the output will be separated using the BY group combinations; however, since multiple combinations can appear on the same page, or a given combination can span pages, it is easy to see how the title would not reflect what is really on the page. This is demonstrated in the following example.

Callout 3 The #BYLINE option is used in the title statement to insert each of the BY variables and their values.

Callout 4 The #BYLINE shows both the BY variables and their values in the title and mimics the BY line generated by the procedure.

Callout 5 This line of text is the BY line generated by the procedure, and in this case it has been continued from the previous page and does not match the title.

Callout 6 The BY group that starts on the current page is reflected in the title Callout 4.

MORE INFORMATION

Examples in Section 7.4.3 and also in 11.3.1 use the #BYVAL option on the TITLE statement.

SEE ALSO

Carpenter (1998) discusses these options in detail. A sasCommunity.org tip written by Mary Rosenbloom demonstrates these options http://www.sascommunity.org/wiki/Tips:Use_BYVAL_to_Write_Better_Titles.

15.1.3 Executing OS Commands

There are several ways to execute operating system commands from within SAS. You can execute these OS commands from within a DATA step or through the use of global statements or macro language statements which are essentially global in this context.

Global Execution

The three global statements include:

  • X
  • %SYSEXEC
  • SYSTASK COMMAND

The Windows example that is shown here collects the names of all the SAS controlled files in the C:TEMP directory. The names are stored in a text file and then read into a SAS data set. This type of operation is common when we want to create a list that is to be stored in macro variables. The full step is first shown using the X statement which is probably the most commonly used statement for executing OS commands and statements.

Callout 1x 'dir "c:	emp*.sas7*" /b/o > c:	empSASFiles.txt';
     Callout 2             Callout 3       Callout 4  Callout 5        Callout 6       
filename flist 'c:	empSASFiles.txt'; Callout 7
data filelist;
infile flist truncover;
input name $20.;
run;

Callout 1 The X statement is used to specify and pass the DIR command to the operating system. Notice that the command to be passed is enclosed in quotes.

Callout 2 The DOS DIR command makes a list of files. DOS commands are still available under Windows even though the current OS is not written using DOS.

Callout 3 Only SAS controlled entities are to be selected by the DIR command. Microsoft requires that Windows paths to be enclosed in double quotes.

Callout 4 Switches are used to limit the results to just the names of the files.

Callout 5 The > symbol is used to route the results of the DIR command to a file.

Callout 6 The file containing the list of items is named.

Callout 7 A FILENAME statement is used to point to the text file containing the list.

The %SYSEXEC statement is a macro language statement that can be executed in open code. As such it is global in nature. In the macro language quote marks are not used as parsing characters; consequently, the DIR command is not quoted.

%sysexec(dir "c:	emp*.sas7*" /b/o > c:	empSASFiles.txt);

The SYSTASK COMMAND statement is also a global statement that can be used to execute OS commands. Its syntax is essentially the same as that used for the X statement.

systask command 'dir "c:	emp*.sas7*" /b/o > c:	empSASFiles.txt';

When the temporary file (C: empsasfiles.txt) is only a means to an end and is of no lasting value, we can create it virtually and avoid actually creating the physical file. The PIPE device type is used on the FILENAME statement to essentially route the file to memory. Here the DIR command is included on the FILENAME statement. Instead of routing the results to a file, they are directly available to the DATA step.

filename flist pipe 'dir "c:	emp*.sas7*" /b/o';

DATA Step Execution

Within the DATA step the SYSTEM function and the CALL SYSTEM routine can be used to execute OS commands. One advantage of this technique is that it is executable, which means that it can be conditionally executed. In this DATA step the CALL SYSTEM routine is used to generate the same list of files, but only after verifying that the directory exists.

data _null_;
  if fileexist('c:	emp') then do;
    call system('dir "c:	emp*.sas7*" /b/o > c:	empSASFiles.txt'),
    end;
  run;

Sub-session Execution Comments

With the exception of the SYSTASK COMMAND statement, when these statements are executed an OS sub-session command window is by default initiated and opened. Under Windows this is seen as a DOS command window. This window must then be closed (the DOS command is EXIT) before SAS can continue with its next statement or operation. This behavior is controlled with the XWAIT system option. Changing this option to NOXWAIT will automatically close this window at the completion of the command.

You will probably notice that even with the NOXWAIT option, the black command window still at least flashes. While this flashing window is not a problem it can be a bit annoying. You can avoid opening the window altogether with the SYSTASK COMMAND statement, but there are other subtle differences. The XMIN option can be used to minimize the command box and a brief command message box. By using the NOXWAIT, NOXSYNC, and XMIN options, the command box does not flash.

options noxwait xmin noxsync;
x 'dir *.*';

The X statement executes synchronously with SAS (XSYNC system option). This means that the SAS process is suspended until the command generated by the X statement has completed. The NOXSYNC system option can be used to allow SAS and the sub-session to execute asynchronously. When operating asynchronously SAS is not suspended while the sub-session command is completed. This can be an issue if a SAS step that follows the X statement depends on the result of the command before the command is complete. The SYSTASK COMMAND statement is by default executed asynchronously.

SEE ALSO

Walsh (2009) goes into more detail on the differences between the X and SYSTASK COMMAND statements. Varney (2008) discusses a number of DOS commands that can be accessed using PIPES.

Quoting issues within an X statement are discussed in the SAS Forum thread http://communities.sas.com/thread/32486?tstart=0. A sasCommunity.org tip discusses the WAITFOR statement which can be used with the SYSTASK COMMAND statement http://www.sascommunity.org/wiki/Tips:Schedule_SAS_Programs_with_SYSTASK_and_WAITFOR.

15.2 Creating User-defined Functions Using PROC FCMP

The FCMP procedure allows you to write, compile, and test DATA step functions and CALL routines that you can then use in the DATA step, with the macro language, and within a number of procedures that allow the use of functions.

In the simplest sense creating a function is fairly straightforward, as is shown in the examples in this book. More complex functions are possible. As is the case with so many of the topics in this book, this section is a teaser. The FCMP procedure is very powerful and the concepts are not that difficult, but look deeper than the presentations in this section – there is a lot more.

MORE INFORMATION

Several user-defined functions appear in Section 12.5.5

SEE ALSO

The classic introduction to the FCMP procedure was written by Jasson Secosky (2007). Adams (2010) and Eberhardt (2011) both also provide nice introductions.

15.2.1 Building Your Own Functions

The first version of the QNUM function which is shown here was written by Rick Langston, senior manager of software development at SAS. It is used to convert a SAS date into a quarter (Q1, Q2, etc.) without the year portion that is returned by the YYQ. format. This allows us to consolidate dates into quarters without regard to year.


				
proc fcmp outlib=work.myfuncs.tmp; Callout 1
   function qnum(date) $; Callout 2
      length yyq4 $4; 
      yyq4=put(date,yyq4.); Callout 3
      if substr(yyq4,3,1)='Q' Callout 4
         then return(substr(yyq4,3,2)); Callout 5
      else return(yyq4); Callout 6
   endsub; Callout 7
run;
options cmplib=(work.myfuncs); Callout 8
data qlabs;
   set advrpt.lab_chemistry
                   (keep=subject labdt);
   qtr=qnum(labdt); Callout 9
   run;
title2 'Quarters without years';
proc freq data=advrpt.lab_chemistry;
   table qtr*visit; Callout 10
   run;

Callout 1 The compiled function is saved in a special data set that includes a packet, which in this case is named TMP.

Callout 2 The FUNCTION statement names the function, lists its arguments in parentheses and, if it is to return a character value, includes the $ before the semicolon.

Callout 3 Use the YYQ. format to translate the date into a quarter.

Callout 4 The third character will be a ‘Q’ if the date was successfully translated using the YYQ. format.

Callout 5 Use the RETURN statement to specify the value to be returned by the function. The SUBSTR function is used to strip off the year (YY) portion of the formatted value.

Callout 6 The date must have been missing or illegal for the YYQ. format.

Callout 7 The FUNCTION statement always ends with the ENDSUB statement.

Callout 8 The CMPLIB option is used to point to the data set that contains the TMP ‘packet’ that holds the function definition.

Callout 9 A new character variable (QTR) with a length of $2 is created using the QNUM function. The lab date is passed into the function as the single argument.

Callout 10 The new variable is used in the TABLE statement.

image shown here

MORE INFORMATION

A variation on the QNUM function is discussed in Section 12.5.5, and a simplified form can be found in Section 15.2.2.

SEE ALSO

An example of a function that calls a macro that contains a PROC FREQ can be found at http://tech.groups.yahoo.com/group/sas_academy/message/438. A FCMP CALL routine is created at

http://tech.groups.yahoo.com/group/sas_academy/message/430. A function is used to calculate a person’s societal age at http://support.sas.com/kb/36/788.html. PROC FCMP is used to create an INFORMAT that converts a fraction to a decimal value in a sasCommunity tip by Mike Zdeb http://www.sascommunity.org/wiki/Tips:Create_an_Informat_from_a_User-Defined_Function.

15.2.2 Storing and Accessing Your Functions

The OUTLIB option on the PROC statement is used to name a storage location for your function. The function is stored in a special SAS data set. You cannot use this data set to also store data nor can you store a function in an existing data set.

From an operational perspective it makes sense to organize the storage of your functions. All the functions associated with the ADVRPT project might be stored in the ADVRPT.FUNCTIONS data set. Those functions dealing with dates could be stored in the DATES packet.

The OUTLIB option specifies the libref (ADVRPT), data set (FUNCTIONS), and the packet (DATES). Function names are unique within a packet but not necessarily across packets. A given packet can contain multiple function definitions, and a given data set can contain multiple packets.

proc fcmp outlib=AdvRpt.functions.Dates;
   function . . . . 

When you want to use a compiled function, the CMPLIB system option is used. This option specifies one or more SAS data sets that contain the packets defined by PROC FCMP. The packet is not specified, and all packets within the data set are made available.

options cmplib=(advrpt.functions);

In the example in Section 15.2.1 the data set MYFUNCS is written to the non-permanent work directory. Here we want to create a more permanent version of this simplified version of the QNUM function. The function QNUM is added to the DATES packet in the permanent data set ADVRPT.FUNCTIONS.

proc fcmp outlib=advrpt.functions.dates;
   function qnum(d) $;
      return(cats('Q',qtr(d)));
   endsub;
run;

We may want to add some other functions to this same data set. Here a new packet (CONVERSIONS) is added to the ADVRPT.FUNCTIONS data set, and we define two functions in one call to the FCMP procedure. These two functions convert from degrees centigrade to Fahrenheit (C2F) and from Fahrenheit to centigrade (F2C).

proc fcmp outlib=Advrpt.functions.Conversions;
   function c2f(c);
      return(((9*c)/5)+32); 
   endsub;
   function f2c(f);
      return((f-32)*5/9); 
   endsub;
run;

Later we can add more conversion functions. Here we add functions to calculate the Body Mass Index (BMI) using both Imperial and Metric units.

proc fcmp outlib=AdvRpt.functions.Conversions;
   function E_BMI(h,w);
      return((w * 703)/(h*h) ); 
   endsub;
   function M_BMI(h,w);
      return(w /(h*h)); 
   endsub;
   run;

It is likely that you will have a number of functions stored in several data sets. To make all of these functions available each of the data sets must be listed on the CMPLIB= system option. Here two data sets are listed. All the functions in all the packets in both of these data sets will be available for use. The exception will be for multiple functions with the same name. Unlike most library searches, the search order across multiple function libraries is from right to left. In the example shown here functions in WORK.MYFUNCS will be found first. The packet is not named in the CMPLIB option; consequently, if the same function name is used in two different packets within the same data set, it will be harder to anticipate which will be used. I would recommend that function names be unique within data set.

options cmplib=(advrpt.functions work.myfuncs);

15.2.3 Interaction with the Macro Language

Functions and routines created using PROC FCMP are typically called from within a DATA step; however, they may also be called from within the macro language by using the macro function %SYSFUNC and the macro statement %SYSCALL.

It is also possible to call or execute a macro from within the function or routine by using the RUN_MACRO function. The following rather silly example demonstrates some of the issues when calling a macro from within a function or routine.

proc fcmp outlib=advrpt.functions.utilities;
subroutine prntcrit(dsn$,kvar $,cvar $); Callout 1
   rc=run_macro('printit',dsn,kvar,cvar); Callout 2
endsub;
run;
%macro printit(); Callout 3
%let dsn  = %sysfunc(dequote(&dsn)); Callout 4
%let kvar = %sysfunc(dequote(&kvar));
%let cvar = %sysfunc(dequote(&cvar));
title2 "&dsn"; Callout 5
proc print data=advrpt.&dsn; Callout 6
%if &kvar ne %then id &kvar;;
%if &cvar ne %then var &cvar;;
run;
%mend printit;
options cmplib=(advrpt.functions); Callout 7
title1 '15.2.3 Macro Language Interface'; Callout 8
data _null_;
   set advrpt.dsncontrol;
   call prntcrit(dsn,keyvars,critvars); Callout 9
   put 'Print ' dsn keyvars critvars;
   run;
proc print data=advrpt.dsncontrol; Callout 10
run;

Callout 1 The SUBROUTINE statement declares this as the routine’s definition. Like with the FUNCTION statement the routine is named. Character argument names are followed by a $.

Callout 2 The first argument of the RUN_MACRO function is the name of the macro to be called. The remaining arguments are the parameters for that macro.

Callout 3 The positional macro parameters are not named on the %MACRO statement. The parameter names will flow from the RUN_MACRO function on through to the macro %PRINTIT Callout 2.

Callout 4 The values of the macro parameters arrive quoted. Since we need them to be unquoted in the application shown here, the DEQUOTE function is called.

Callout 5 TITLE2 will be displayed when the PROC PRINT executes. Although the TITLE1 statement will have been executed Callout 8, within the domain available to the compiled routine its definition is not available, and will, therefore, remain undefined.

Callout 6 The PROC PRINT within the macro %PRINTIT is constructed using the macro parameters.

Callout 7 The function library is specified.

Callout 8 TITLE1 is defined before the DATA step that will call the routine; however, this title will not be available to the macro executed by the PRNTCRIT routine.

Callout 9 The PRNTCRIT routine is called using three variables from the ADVRPT.DSNCONTROL data set. The variables in the routine call must be in the same order as they are defined Callout 2. The PRNTCRIT routine is called for each observation on the incoming data set. The routine calls and executes the macro %PRINTIT. Unlike the CALL EXECUTE routine. which pushes the macro call to a stack, %PRINTIT will be executed immediately.

Callout 10 The TITLE1 will be honored, but the TITLE2 will be undefined.

proc fcmp outlib=advrpt.functions.utilities;
subroutine prntcrit(dsn$,kvar $,cvar $);
   %printit(dsn,kvar,cvar);
. . . . . 

Because functions and routines are compiled, we cannot use a macro call directly within the function definition. If we had attempted to specify the macro call directly as shown here, %PRINTIT would have executed while the PRNTCRIT routine was being compiled. Macro calls such as this one would be used to generate routine or function code. Macros that are to be executed during function execution should be specified with the RUN_MACRO function as was shown above.

MORE INFORMATION

The DEQUOTE function is introduced in Section 3.6.7.

SEE ALSO

Chapter 8 in Carpenter’s Complete Guide to the SAS® Macro Language, 2nd Edition (Carpenter, 2004) discusses the use of macros and macro variables within the context of compiled code.

15.2.4 Viewing Function Definitions

User-defined functions do not appear in the SASHELP.VFUNC view or in the DICTIONARY.FUNCTIONS table. However, under Windows you can see both the list of available functions and their attributes through the use of the FCMP Function Editor.

To start this editor, go to SOLUTIONS ANALYSIS FCMP FUNCTION EDITOR. The list of available data sets and the functions that they contain is shown in the left pane. Selecting a function brings up the editor dialog box, which allows you to see the details of the function’s definition.

image shown here

15.2.5 Removing Functions

Although functions and routines are stored in data sets, you cannot use standard data management techniques to delete an instance of a function or a routine. Fortunately the FCMP procedure comes with the DELETEFUNC and DELETESUBR statements that can be used for this purpose.

For the purposes of this example let us assume that a version of the function START has been stored in two different locations (two different data sets). The search order for multiple data sets is from right to left (this is the opposite order for searches across libraries, e.g., formats, autocall). The START function is to be written so that it will return the first date of the specified interval type.

proc fcmp outlib=work.funcs.dates; Callout 1
function start(int$,date);
   return(intck(int,date,0,'b'));
   endsub;
run;
proc fcmp outlib=advrpt.functions.dates; Callout 2
function start(int$,date);
   return(intnx(int,date,0,'b')); Callout 3 
   endsub;
run;
options cmplib=(advrpt.functions work.funcs ); Callout 4

Callout 1 A temporary location is set up to hold the START function. Unfortunately this function has been specified incorrectly using the INTCK function and will fail.

Callout 2 The permanent data set to collect functions in the DATES packet is specified.

Callout 3 The correct version of START, which uses the INTNX function, is stored in the permanent location.

Callout 4 The CMPLIB option specifies that the WORK.FUNCS data set will be searched first, and this means that the bad version of the START function Callout 1 will be found and used.

proc fcmp outlib=work.funcs.dates; Callout 5
   deletefunc start; Callout 6
   run;

We need to have the ability to remove the bad definition of START from WORK.FUNCS.DATES. This can be done using the DELETEFUNC statement.

Callout 5 PROC FCMP is called with the OUTLIB option pointing to the packet containing the bad definition of START.

Callout 6 The DELETEFUNC statement can then be used to delete the specific function.

data list;
do d = '01jan2010'd to '05feb2010'd;
   styr = start('year',d); Callout 7
   stmo = start('month',d); Callout 8
   output;
   end;
   format d styr stmo date9.;
   run;

Using the function libraries defined above Callout 4, the version of START in ADVRPT.FUNCTIONS.DATES will now be the only version available.

Callout 7 The first day of the year that contains the date stored in D is returned by the function START.

Callout 8 The START function returns the first day of the month that contains the date in D.

MORE INFORMATION

You can also delete functions and routines by using the FCMP Function Editor (see Section 15.2.4).

15.3 Reading RTF as Data

RTF is a proprietary document file format developed by Microsoft Corporation in the late 1980s. Unlike an MS Word .DOC binary file, an RTF file can be read by text editors. This means that if we treat an RTF file as text, we can use SAS to read and write the RTF file as data, and this opens the door for the power and flexibility associated with the use of the SAS DATA step and the SAS macro language.

The example shown in this section modifies a CONsolidated Standards Of Reporting Trials, CONSORT, flow diagram by filling in the blanks.

SEE ALSO

These specific examples are presented in more detail in Carpenter and Fisher (2011).

15.3.1 RTF Diagram Completion

The layout of the CONSORT table depends on the study design. This includes the number of ARMS and the phases of the study. The techniques discussed in this section, however, are completely independent of the study design. The first step in this process is to create a template form of the CONSORT table. This RTF table will contain all the needed information with blank fields. This figure shows the “Enrollment” portion of a CONSORT table, which will show the number of subjects and their status relative to the study. Typically the N= values would be filled in by hand once they had been determined.

image shown here

The RTF CONSORT table can easily have over a dozen fields that require completion. In the process described below, each field will be assigned a code unique to the table. The entire table (RTF file) will then be read as data and the codes will be translated into the final values through the use of DATA step functions. The resulting modified table will be rewritten, again as an RTF file, where it will then be available for use by a word processor.

15.3.2 Template Preparation

The template is prepared for use by SAS by filling in each of the individual fields using unique codes. Here the unique codes for the first six fields are TOTASSESSD, TOTEXCL, INELIG, DECLIN, EXCLOTH, and NRAN. For our purposes we are assuming that these names never occur otherwise in the table. Other than being unique, the code that you choose is unimportant, but for a more complicated table the field code names can be used to help make sure that the values are inserted in the correct location.

image shown here

15.3.3 RTF as Data

Fortunately we need to know very little about RTF code in order to work with it using SAS. A quick look at a portion of the RTF code that generated the figure shown in the previous section shows a text language which is mostly not human readable. However, a closer inspection shows one of our designated keywords (DECLIN).

par }{
tlchfcs1 af0afs16 ltrchfcs0 f3fs16lang0langfe1033langnp0
fs16lang4105langfe1033langnp4105insrsid4260155charrsid1516310   }{
t
f1fs20lang4105langfe1033langnp4105insrsid1909421 DECLIN}{
tlchfcs1 
par }{
tlchfcs1 af0afs16 ltrchfcs0 f3fs16lang0langfe1033langnp0

Our approach will be to have SAS read the RTF text strings, find the appropriate codes, replace the codes with the values of interest, and then replace the modified RTF text strings. The search and replace operations will be handled by using the TRANSTRN function, which replaces all occurrences of the second argument with the third argument. For our purposes there should only be one occurrence for each of our codes.

The DATA step used to read and write the RTF CONSORT table is fairly straightforward. RTF does not have a fixed maximum record length; however, the length is generally under 500 characters. Here the LRECL is set to 3000 – just in case. The incoming RTF file is designated by the fileref CONFFILE1. The new version of the CONSORT table is written to the file named in the CONFILE2 fileref. Through the use of the automatic variable _INFILE_ we read each RTF line as an entire entity. This string is then searched and the appropriate codes are replaced. In this example the TRANSTRN function replaces the text ‘TOTASSESSED’ with the appropriate number, which we have provided (345). In the figure to the left we can see that the placeholder codes that we used in the template version of the table have been replaced with the values supplied in the SAS program. In the paper cited above, (Carpenter and Fisher, 2011) macro code is shown that provides an automated metadata driven coding solution.

filename confile1 "C:	empCONSORT_Diagram1.rtf";
filename confile2 "C:	empCONSORT_Diagram2.rtf";
data _null_;
infile confile1 lrecl=3000;
input;
_infile_ = transtrn(_infile_,'TOTASSESSED','345'),
_infile_ = transtrn(_infile_,'TOTEXCL',    '56'),
_infile_ = transtrn(_infile_,'INELIG',     '35'),
_infile_ = transtrn(_infile_,'DECLIN',     '17'),
_infile_ = transtrn(_infile_,'EXCLOTH',    '4'),
_infile_ = transtrn(_infile_,'NRAN',       '289'),
file confile2  lrecl=3000;
put _infile_;
run;

image shown here

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset