If I run this:
%let teststr=a, %*b, %*c, %;
%put %qscan(&teststr.,2,%str(*));
It runs perfectly fine and return:
b%
However if I put this into a macro:
%macro test;
%let teststr=a, %*b, %*c, %;
%put %qscan(&teststr.,2,%str(*));
%mend;
%test
Then there is no output. Does anyone know why?
Thanks,
Jason
@acmilannesta wrote:
Thank you, Tom.
That works great. I am still a beginner for SAS.
Could you please tell what's the difference between a %let statement and a call symputx?
Does a %superq could mask some macro symbols such as % and *. I tried to use %bquote and %nrbquote, but that doesn't work.
A %LET statement is macro code. CALL SYMPUTX() is a function you can use with normal SAS code instead.
There are rules for how the SAS macro processor parses the text to see if there is any work for it. That leads to the need for the extra % mentioned so that it wouldn't see the percent in
%)
as instructions to treat the right parenthesis as part of the string instead of the closing parenthesis to the macro function call.
But in regular SAS code strings are enclosed in quotes. And if you use single quotes then the macro processor ignores them. So by using a data step to set the macro variable value you don't need to worry if the value has any characters that the macro processor considers special. However using CALL SYMPUTX() will not inject any macro quoting into the value of the macro variable. So you need to take care when using it in macro code since it might contain characters, like comma in this case, that will have a special meaning if not macro quoted.
Here is another trick set a macro variable to avoid worrying about a lot of the macro quoting that you can use in a place where you could not add a data step. Enclose the string in single quotes and then use the %sysfunc(), or if you need macro quoting the %qsysfunc(), macro function to call the DEQUOTE() function to remove the quotes.
%let mvar=%qsysfunc(dequote('A %,B%*'));
The eternal mystery that is SAS macro quoting. Why? I don't really know. I've never had much success with the escape characters, but I do know that do use the percent sign in this context, you need %nrstr.
%macro test;
%let teststr = %nrstr(a%*b%*c);
%put %scan(&teststr, 2, %str(*));
%mend test;
%test;
You can use %qscan, or %scan - it makes little difference.
Both of your examples do not work:
24 %let teststr=a, %*b, %*c, %; 25 %put %qscan(&teststr.,2,%str(*)); ERROR: Macro function %QSCAN has too many arguments. 26 27 %macro test; 28 29 %let teststr=a, %*b, %*c, %; 30 %put %qscan(&teststr.,2,%str(*)); 31 %mend; 32 33 34 35 %test WARNING: Argument 2 to macro function %QSCAN is out of range.
Hi @acmilannesta,
Your macro TEST doesn't work for two reasons:
1 options symbolgen; 2 3 %macro test; 4 %let teststr=a, %*b, %*c, %; 5 %put Length: %length(&teststr); 6 %mend; 7 8 %test SYMBOLGEN: Macro variable TESTSTR resolves to a, Length: 2 9 10 %let teststr=a, %*b, %*c, %; 11 %put Length: %length(&teststr); SYMBOLGEN: Macro variable TESTSTR resolves to a, %*b, %*c, % Length: 14
Similarly, your open-code approach doesn't work either: After resolving &teststr. to a string containing unquoted commas %QSCAN has in fact "too many arguments" (see error message in Kurt Bremser's post). How did you obtain the result b% given that this substring is not contained in the value of TESTSTR?
Use %NRSTR, as recommended by @LaurieF, and the code works inside and outside a macro (with %SCAN and %QSCAN):
1 options symbolgen; 2 3 %macro test; 4 %let teststr=%nrstr(a, %*b, %*c, %%); 5 %put %scan(&teststr.,2,%str(*)); 6 %mend; 7 8 %test SYMBOLGEN: Macro variable TESTSTR resolves to a, %*b, %*c, % SYMBOLGEN: Some characters in the above value which were subject to macro quoting have been unquoted for printing. b, % 9 10 %let teststr=%nrstr(a, %*b, %*c, %%); 11 %put %scan(&teststr.,2,%str(*)); SYMBOLGEN: Macro variable TESTSTR resolves to a, %*b, %*c, % SYMBOLGEN: Some characters in the above value which were subject to macro quoting have been unquoted for printing. b, %
Note that I used the double percent sign so as to avoid that the closing parenthesis is masked and thus not recognized.
Thank you so mcuh, FreelanceReinha
It works! I tried to use %nrstr() as well, but the piece I miss is the trailing % sign. Could you explain a little bit more about the rationale:
"Note that I used the double percent sign so as to avoid that the closing parenthesis is masked and thus not recognized."
@acmilannesta wrote:
I tried to use %nrstr() as well, but the piece I miss is the trailing % sign. Could you explain a little bit more about the rationale:
"Note that I used the double percent sign so as to avoid that the closing parenthesis is masked and thus not recognized."
Normally you use the combination %) in a %NRSTR (or %STR) call to make an unmatched closed parenthesis a part of the value of a macro variable. Without the percent sign masking it, the parenthesis would be interpreted as the closing parenthesis of the %NRSTR(...) call (see documentation Using Unmatched Quotation Marks and Parentheses with %STR and %NRSTR).
In your example, however, the parenthesis is meant to be the closing parenthesis of the %NRSTR(...) call and the percent sign is not meant as a masking tool for it. To explain this special requirement to the macro processor, I used the double percent sign. The first percent sign masks the second, so the second is regarded as text, not as a macro trigger. Then, the closing parenthesis is not masked and works as desired. (See the note at the bottom of the short section Using % Signs with %STR in the documentation.)
Using the macro variable value in a macro is not the issue. But you need to use macro quoting in that goofy string BEFORE passing it to the %qscan() function to avoid issues because of the embedded commas.
How are you generating that macro variable? I am surprised that the %LET statement works in open code since it contains a macro comment in the middle of the value.
If you really want to generate a macro variable with such mess of macro triggers inside of it then generate it from data. Then later you can add macro quoting, for example by using %superq() macro function.
107 data _null_; 108 call symputx('teststr','a, %*b, %*c, %'); 109 run; NOTE: DATA statement used (Total process time): real time 0.04 seconds cpu time 0.00 seconds 110 %let teststr=%superq(teststr); 111 %put %qscan(&teststr.,2,%str(*)); b, % 112 113 %macro xx; 114 %put %qscan(&teststr.,2,%str(*)); 115 %mend xx; 116 %xx; b, %
Thank you, Tom.
That works great. I am still a beginner for SAS.
Could you please tell what's the difference between a %let statement and a call symputx?
Does a %superq could mask some macro symbols such as % and *. I tried to use %bquote and %nrbquote, but that doesn't work.
@acmilannesta wrote:
Thank you, Tom.
That works great. I am still a beginner for SAS.
Could you please tell what's the difference between a %let statement and a call symputx?
Does a %superq could mask some macro symbols such as % and *. I tried to use %bquote and %nrbquote, but that doesn't work.
A %LET statement is macro code. CALL SYMPUTX() is a function you can use with normal SAS code instead.
There are rules for how the SAS macro processor parses the text to see if there is any work for it. That leads to the need for the extra % mentioned so that it wouldn't see the percent in
%)
as instructions to treat the right parenthesis as part of the string instead of the closing parenthesis to the macro function call.
But in regular SAS code strings are enclosed in quotes. And if you use single quotes then the macro processor ignores them. So by using a data step to set the macro variable value you don't need to worry if the value has any characters that the macro processor considers special. However using CALL SYMPUTX() will not inject any macro quoting into the value of the macro variable. So you need to take care when using it in macro code since it might contain characters, like comma in this case, that will have a special meaning if not macro quoted.
Here is another trick set a macro variable to avoid worrying about a lot of the macro quoting that you can use in a place where you could not add a data step. Enclose the string in single quotes and then use the %sysfunc(), or if you need macro quoting the %qsysfunc(), macro function to call the DEQUOTE() function to remove the quotes.
%let mvar=%qsysfunc(dequote('A %,B%*'));
Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 25. Read more here about why you should contribute and what is in it for you!
SAS' Charu Shankar shares her PROC SQL expertise by showing you how to master the WHERE clause using real winter weather data.
Find more tutorials on the SAS Users YouTube channel.