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-2024.png

Don't miss out on SAS Innovate - Register now for the FREE Livestream!

Can't make it to Vegas? No problem! Watch our general sessions LIVE or on-demand starting April 17th. Hear from SAS execs, best-selling author Adam Grant, Hot Ones host Sean Evans, top tech journalist Kara Swisher, AI expert Cassie Kozyrkov, and the mind-blowing dance crew iLuminate! Plus, get access to over 20 breakout sessions.

 

Register now!

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.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

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