BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
WimB
Fluorite | Level 6

I'm trying to write where any given macro variable can be numeric or character as the list of possible input value could be any integer, possibly preceded or followed by a character (i.ee = -1, 0, 1, d1, w9e), but something is off. See below for the simplified code:

 

Checking if variable is integer:

%macro isnum (mv);
   %eval(not %sysfunc(verify(&mv,-0123456789)));
%mend isnum;

%macro DefineDate(dt1,dt2,dt3);														
	...				
	%do i = 1 %to 3;
		%put Test dt&i. = &&dt&i.;
		%if %length(&&dt&i.) ne 0 %then %do;
			%put Variable dt&i. = &&dt&i.;
			%if %isnum(&&dt&i.) = 1 %then %do;
				%put dt&i. isnum successful;
			%end;
			%else %do;
				%put dt&i. isnum did not run;
			%put dt&i. numericity is %isnum(&&dt&i.);
		%end;
		%else %put dt&i. does not exist;
	%end;	
%mend;
%DefineDate(dm1,0)

The output to the log is:

Test dt1 = dm1
Variable dt1 = dm1
dt1 isnum did not run
dt1 numericity is 0;
Test dt2 = 0
Variable dt2 = 0
dt2 isnum did not run
dt2 numericity is 1;
Test dt3 =
dt3 does not exist

 

I can't understand why I can't get the %IF conditional to run in the second step, despite it returning 1 in the identical put statement.

Thank you

1 ACCEPTED SOLUTION

Accepted Solutions
WimB
Fluorite | Level 6

I just been able to solve it!

 

%if %sysfunc(prxmatch('^-?\d+$',&&dt&i.)) = 1 %then %do;

This did the trick for me and should be easily changable should the requirements someday change to include decimals 🙂

View solution in original post

15 REPLIES 15
Reeza
Super User
I think the NOT in the %eval is incorrect. Would the notdigit or INPUTN maybe be easier to use than verify? If you explain your latter usage of these values, there may be other options.
novinosrin
Tourmaline | Level 20

In my opinion @Reeza is bang on target with notdigit being the sweetest. However, You could use %sysevalf to evaluate to a Boolean result. I learned that from Guru of Gurus @data_null__ . Little too late and tired in Chicago night, but I hope I comprehended the topic. 

WimB
Fluorite | Level 6
I tried notdigit, but it only works on character variables and then I'd get the error for numeric inputs that there is a NUM variable where notdigit expects a CHAR variable.

Also not sure about the "not" in the %eval being incorrect: if it was, why would it return a 1 in the put statement for the correct variable?

I'll struggle on for a bit trying to see another solution with notdigit and ssyevalf. Report back later.
Reeza
Super User
All macro variables are character to start so anydigit will work, make sure to not use quotes.
WimB
Fluorite | Level 6

Ok, I'll retry and update in a bit. Thanks for your time, much appreciated!

novinosrin
Tourmaline | Level 20

a simple test-log report

 

2078 %put %sysfunc(notdigit(a123));
1

2081 %put %sysfunc(notdigit(123));
0

Reeza
Super User
Do you need to account for decimals and percentages or will it always be integers?
novinosrin
Tourmaline | Level 20

brilliant question and %sysevalf has the answer

 

log:
 %put %SYSEVALF( %sysfunc(notdigit(123.22)) , boolean );
1
I think my usage is wrong but we are close

WimB
Fluorite | Level 6

The %isnum macro also returned 1, despite the %IF not returning true for checking = 1

 

%put dt&i. numericity is %isnum(&&dt&i.)

This returns dt2 numericity is 1, so I got that far too.

 

I also tried NOTDIGIT and I got this in the log:

 

ERROR: Required operator not found in expression: notdigit(&&dt&i.) = 0 
ERROR: The macro DEFINEDATE will stop executing.

 

 

I think I'll give up on these methods for now and try to use prxmatch for a bit. This is breaking my mind why it returns 1 in a %PUT, but can't evaluate %IF %ISNUM(&&dt&i.) = 1 as true at the same time with all other proposed solutions giving me errors.

novinosrin
Tourmaline | Level 20

I will test tomorrow morning and get to the bottom of it but I'm more than 100% certain , somebody else will give you the much needed solution while my night passes by sleeping. Hang in there

WimB
Fluorite | Level 6

I just been able to solve it!

 

%if %sysfunc(prxmatch('^-?\d+$',&&dt&i.)) = 1 %then %do;

This did the trick for me and should be easily changable should the requirements someday change to include decimals 🙂

FreelanceReinh
Jade | Level 19

@WimB wrote:

 

This did the trick for me and should be easily changable should the requirements someday change to include decimals 🙂


For more general types of numeric values (including decimals and scientific notation) there's also the %DATATYP Autocall Macro.

Tom
Super User Tom
Super User

The real  problem is that you included a semi-colon in your macro "function".  A macro that only generates part of a statement cannot generate a semi-colon because that will prematurely terminate any statement that you try to use it in.

 

1    %macro isnum (mv);
2       %eval(not %sysfunc(verify(%superq(mv),-0123456789)))
3    %mend isnum;
4
5    %put %isnum(fred);
0
6    %put %isnum(123);
1
7    %put %isnum(-1.2.3);
0
8    %put %isnum();
1

 

SAS Innovate 2025: Save the Date

 SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!

Save the date!

How to Concatenate Values

Learn how use the CAT functions in SAS to join values from multiple variables into a single value.

Find more tutorials on the SAS Users YouTube channel.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 15 replies
  • 11161 views
  • 11 likes
  • 6 in conversation