Hi:
The description of the NOTDIGIT function says that NOTDIGIT function searches a string for the first occurrence of any character that is not a digit. If such a character is found, NOTDIGIT returns the position in the string of that character. If no such character is found, NOTDIGIT returns a value of 0.
So, IF your character variable has all numbers, then the DO block will NOT be executed. However, more about this later.
In your original post, you said:
i'm stepping through a data step with 20 vars and i have a if / then condition that determines to call the macro or not.
if notdigit(prod,1) > 0 then
%sel(prod );
this code calls the macro every step through the data step. is there another way to conditionally process this?
This code does NOT call the macro program or not. Your macro code is NOT being executed conditionally...not exactly. There is a HUGE difference between a macro %IF/%DO and a regular DATA step program with a %mac invocation. When you have the kind of syntax that you show, essentially, at compile time, all your %sel(...) invocations are being expanded into code like this (shown for PROD and CRED variables). This expansion (or resolution) happens at code COMPILE time. So by the time your program executes, these are the complete sets of IF statements that SAS is actually executing or not executing:
[pre]
** for PROD section of code;
if notdigit(prod,1)> 0 then
do;
bad_dig=substr(prod,notdigit(prod,1),1);
if bad_dig ne '.' then
do;
bad_col=notdigit(prod,1);
bad_var="prod";
keep prod bad_var;
output;
end;
end;
** for CRED section of code;
if notdigit(cred,1)> 0 then
do;
bad_dig=substr(cred,notdigit(cred,1),1);
if bad_dig ne '.' then
do;
bad_col=notdigit(cred,1);
bad_var="cred";
keep cred bad_var;
output;
end;
end;
[/pre]
So by the time SAS executes these statements, the DO block contained in the %SEL macro program will be executed based on the NOTDIGIT test in the DATA step IF statement. So the resolved statements are only going to be executed AT ALL if the results of using the NOTDIGIT function return a result greater than 0.
That being the case, let's turn our attention to the NOTDIGIT function. If you are using the NOTDIGIT function on a character variable, unless your numbers fill the entire length of the variable, you might be surprised to find that you get different results for the value of the NOTDIGIT function, depending on whether you have trailing blanks in the character variable value (which is possible). Consider the following program:
[pre]
data _null_;
length string $20;
infile datalines;
input string $;
test1 = notdigit(trim(string),1);
test2 = notdigit(string,1);
put '=======>' string= test1= test2=;
return;
datalines;
11a1
2222
333z3
4444
12345678901234567890
;
run;
[/pre]
Note that I have given the STRING variable an explicit length of 20 characters, yet of my 5 observations, only the last observation completely uses up all 20 positions allocated to the variable length. The TEST1 variable uses the NOTDIGIT function with the TRIM function (to strip off trailing blanks (because a character variable that does not "fill" its length will be padded to the right with blanks). The TEST2 variable uses the NOTDIGIT function in the same way that you do in your program, without trimming or stripping out the trailing blanks. The SAS log shows different values for the TEST1 vs the TEST2 variable:
[pre]
SAS Log:
=======>string=11a1 test1=3 test2=3
=======>string=2222 test1=0 test2=5
=======>string=333z3 test1=4 test2=4
=======>string=4444 test1=0 test2=5
=======>string=12345678901234567890 test1=0 test2=0
[/pre]
As you can see from my results, shown in the log, that observation 2 (2222) and observation 4 (4444) in the untrimmed comparison show a value for TEST2 of 5 -- which would be the position of the first blank that pads the character variable value. So, that means it is possible for your NOTDIGIT function to return a value greater than 0 for your character variables, unless you are absolutely sure that your variable values completely fill up the length of the variable field.
Rather than focus on whether or not your macro code is being called conditionally, one thing to do would be to make your code more efficient. For example,by my count, your program is generating a call to the NOTDIGIT function possibly 3 times -- for EVERY variable you test. It would be more efficient to do execute the NOTDIGIT function one time, make a temporary variable and then test this temporary variable or use it in further function calls (like the SUBSTR function) -- something like this:
[pre]
notdig_val = notdigit(trim(prod),1); /* execute the NOTDIGIT function one time */
if notdig_val> 0 then
do;
bad_dig=substr(prod,notdig_val,1);
if bad_dig ne '.' then
do;
bad_col=notdig_val;
bad_var="prod";
keep prod bad_var;
output;
end;
end;
[/pre]
This change for efficiency purposes might mean that you need to redesign your macro program code a bit. Just remember that the macro processor is just acting like a big typewriter and that your %sel(...) macro program invocation is being resolved or expanded at code COMPILE time -- by the time your program executes, all the %sel(...) references are gone and have been replaced by the now complete DATA step IF statement. Your macro program is just saving you some tedious typing or repetitive statements for every variable you want to test.
cynthia