BookmarkSubscribeRSS Feed
SASJedi
Ammonite | Level 13

 

Quoting in SAS Macro ProgrammingQuoting in SAS Macro Programming

Hey, there, fellow SAS coders! Have you ever struggled with when, where, and how to properly quote values when programming in SAS macro? So have I 😄 So I thought I’d share some of the tips and tricks I've found useful during my quarter century (😮!) as a SAS programmer. I'm putting together a presentation entitled Quoting in SAS® Macro Programming, and I’ll present it live during the “Ask the Expert” webinar on October 11th, 1 PM – 2 PM EDT. During the demonstration, I'll showcase the effects of underquoting and overquoting macro variables, and share some effective troubleshooting and correction techniques.

Bring your questions - I’ll host a live Q&A session at the end of the webinar!

 

In this session you will learn:

  • When and why quoting is necessary.
  • The perils of improper quoting.
  • Macro quoting techniques including: %STR, %NRSTR, %BQUOTE and %SUPERQ and the “Q” functions - %QSYSFUNC, %QSUBSTR, etc.

Reserve your spot for the webinar.

 

Want more tips? Be sure to subscribe to the Ask the Expert board to receive follow-up Q&A, slides, and recordings from this and other SAS Ask the Expert webinars.

 

Can't join the live event? You can view this and other Ask the Expert sessions on-demand here. 

 

And as always -  May the SAS be with you!

Mark 

Check out my Jedi SAS Tricks for SAS Users
11 REPLIES 11
Quentin
Super User

This sounds EXCELLENT!  You can never hear macro quoting explained too many times.  I look forward to hearing the Jedi approach.

 

Also very happy to see that %NRBQUOTE is not on the agenda.  I think %NRBQUOTE should be officially deprecated.  I've yet to find an example where %NRBQUOTE provided some useful functionality that couldn't be provided by the four you list: %STR, %NRSTR, %BQUOTE and %SUPERQ.  In my mind, %SUPERQ is what %NRBQUOTE was probably intended to be.  If I was rich, I would announce a $1M prize for anyone who could provide an example where %NRBQUOTE was needed. : )

 

 

Ksharp
Super User
/*The difference between %SUPERQ and %NRBQUOTE is :
%SUPERQ would mask '& %' immediately if macro variable contains these special character
%NRBQUOTE would not mask  '& %' ,and would resolve these further . Like this example :
*/
%let a=aa&b;
%let b=bb ;

%put %superq(a) ;
%put %nrbquote(&a) ;

Ksharp_0-1664533675662.png

 

Quentin
Super User

I agree @Ksharp, that is the difference between %NRBQUOTE and %SUPERQ.

 

My point is that I don't think %NRBQUOTE provides any useful functionality, beyond that offered by %str %nrstr %bquote %superq.

 

The only useful thing that %NRBQUOTE does is prevent & from being seen as the AND operator in an eval.  The docs say:

 

The %NRBQUOTE function is useful when you want a value to be resolved when first encountered, if possible, but you do not want any ampersands or percent signs in the result to be interpreted as operators by an %EVAL function.

(I don't think % is an operator for %EVAL, not sure what that part of the documentation means.)

 

 

This will error because the implied %eval sees the & as a logical AND operator:

%macro foo(value=) ;
  %if &value eq %nrstr(a & b) %then %put match ;
  %else %put no match ;
%mend foo ;

%foo(value=a & b)

 

This will not:

%macro foo(value=) ;
  %if %nrbquote(&value) eq %nrstr(a & b) %then %put match ;
  %else %put no match ;
%mend foo ;

%foo(value=a & b)

 

So that is I guess some functionality, but I'd opt for:

%macro foo(value=) ;
  %if %superq(value) eq %nrstr(a & b) %then %put match ;
  %else %put no match ;
%mend foo ;

%foo(value=a & b)

Which will mask everything in resolved value of the macro variable VALUE.  

 

I don't think I've ever had a case where I thought "I want to resolve every macro trigger, for multiple levels of resolution, but if there is an & symbol I don't want it be interpreted as logical AND".

 

I tried thinking of a convoluted case where %NRBQUOTE might be useful with multiple levels of resolution, the closest I could come was something like:

data _null_ ;
  call symput("X","a & b") ;
  call symput ("Y", '&x') ;
run ;


%macro foo(macvar=) ;
  %if %nrbquote(&&&macvar) = %nrstr(a & b) %then %put match ;
  %else %put nomatch ;
%mend foo ;

%foo(macvar=y)

But in general, if I'm thinking about masking symbols, I'm much more worried about a&b where &b will be seen as a macro reference.  %NRBQUOTE can't help there.  It's hard to imagine a setting where  I would want to mask the AND operator a & b , but not mask the macro reference a&b.

 

I'd be interested to see any useful uses of %NRBQUOTE.

 

Ksharp
Super User
Yeah. I admitted %NRBQUOTE is rare to use in reality .
And I think "Macro quoting function" is the core of macro language .
PaigeMiller
Diamond | Level 26

@Quentin wrote:

This sounds EXCELLENT!  You can never hear macro quoting explained too many times.  I look forward to hearing the Jedi approach.


My sentiments exactly!

--
Paige Miller
SASJedi
Ammonite | Level 13

LOL!!! NOTHING sparks spirited discussion amongst SAS programmers like SAS Macro quoting! The webinar Q&A should be quite ... interesting! 😆

Check out my Jedi SAS Tricks for SAS Users
sbxkoenk
SAS Super FREQ

Hello _ALL_,

 

Of course I struggled with SAS macro quoting for years.
But, after 30 years of SAS-experience, I'm not doing so bad anymore.

 

Indeed, you cannot hear enough about it (everyone has their own, possibly instructive, perspectives)

, but I don't think I'm going to have time to hear @SASJedi at work (in this webinar)

, but I can only recommend it.

It could save you a lot of frustration in your 1,000 next macros (and counting).

I sincerely hope that this seminar offers you the "aha-erlebnis"ms that will take you on for years to come.

 

Cheers,

Koen

SASJedi
Ammonite | Level 13

The demos and code this presentation were developed using SAS on Demand for Academics (SoDA). If you want your own copy to run there, log onto SoDA, then after the presentation tomorrow, submit this code from SAS Studio to grab and unpack your copy:

filename macro url "https://raw.githubusercontent.com/SASJedi/sas-macros/master/unpackzip.sas";
%include macro;
options dlcreatedir;
libname x "~/Ask the Expert";
libname x "~/Ask the Expert/A Fine Quotation - Macro Quoting";
libname x clear;
options nodlcreatedir;

%let path=~/Ask the Expert/A Fine Quotation - Macro Quoting;
filename localzip "&path/local.zip" ;
proc http url=
"https://github.com/SASJedi/presentations/raw/master/A%20Fine%20Quotation%20-%20Macro%20Quoting.zip"
	out=localzip;
run;
%unpackzip(&path,local.zip)
/* Activate some useful macros */
%include "&path/autocall/*.sas";

and may the SAS be with you!
Mark

Check out my Jedi SAS Tricks for SAS Users
Quentin
Super User

Webinar was excellent, Mark.  I always enjoy (and am impressed by) presentations with live SAS code.

 

I'm intrigued by your comment that Studio doesn't show delta characters from %PUT _user_ ; 

 

The delta characters must be there in the value stored in the symbol table.  I wouldn't think the %PUT statement works any different in studio.  I wonder if this is just a case of the browser not knowing how to display the non-printable characters.  One way to test that theory would be to use PROC PRINTTO to send the log to a text file, and then run the %PUT _USER_ and took at the log file outside of studio.  I would expect the text file to have the non-printable characters.  Or maybe if you look at the raw html code in the studio pane you'd be able to see the unprintable characters there?  Just guesses.

 

 

SASJedi
Ammonite | Level 13

It's certainly about the way HTML renders, although saving the log file and viewing it in Notepad++ still didn't show the delta characters. However, if you use PROC PRINTTO to redirect the log to a text file and download that, you can see them there. I ran this example in SAS on Demand for Academics:

%macro test;
	proc printto log='~/log.txt';
	run;
	%local C1 C2;
	%let C1=%nrstr(AT&T);
	%let C2=%nrstr(= ; %(%) %' %" %% ~ & | ¬ ^ + # - * , / < > AND NOT OR EQ GE GT IN LE LT NE );
	%put NOTE: Value dump to log using _local_.;
	%put _local_;
	%put NOTE: Characters get unquoted automatically for display when written to the log.;
	%put NOTE- %superq(C2);
	proc printto;run;
%mend;

%test

And when I downloaded the text file and viewed it in Notepad++, the delta characters where visible:

NOTE: Value dump to log using _local_.
TEST C1 ATT
TEST C2          ¬  #       AND NOT OR EQ GE GT IN LE LT NE 
NOTE: Characters get unquoted automatically for display when written to the log.
        = ; () ' " % ~ & | ¬ ^ + # - * , / < > AND NOT OR EQ GE GT IN LE LT NE


As you can see, the "delta character" processing is a bit more complex than I went into during the seminar. Besides the "before and after" non-printable characters ( and ), you can see that all of the special characters were transformed into other, non-printable characters to avoid triggering macro processing. When the value is unquoted, like when they are printed in the log that second time, the non-printable characters are translated back to the original special characters.  

Check out my Jedi SAS Tricks for SAS Users
Quentin
Super User

Thanks for showing that, @SASJedi !  

 

I remember at a conference hearing some SAS rock star (Ron Cody perhaps) say at conferences, he hangs out in the beginner tutorials, because you can learn so much, and you never know what you will learn.  While I think I have a good grasp of macro quoting, your side comment about this Studio idiosyncrasy was super-valuable and I will try to file it away in my memory. And I very much enjoyed your quotations about quotes interspersed in the presentation.

hackathon24-white-horiz.png

The 2025 SAS Hackathon has begun!

It's finally time to hack! Remember to visit the SAS Hacker's Hub regularly for news and updates.

Latest Updates

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
  • 11 replies
  • 2258 views
  • 26 likes
  • 5 in conversation