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

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

1 ACCEPTED SOLUTION

Accepted Solutions
Tom
Super User Tom
Super User

@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%*'));

View solution in original post

10 REPLIES 10
LaurieF
Barite | Level 11

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.

Kurt_Bremser
Super User

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.
FreelanceReinh
Jade | Level 19

Hi @acmilannesta,

 

Your macro TEST doesn't work for two reasons:

  1. %* (inside a macro) is apparently interpreted as the beginning of a macro comment so that TESTSTR contains only two characters: a, (see log below).
  2. The unquoted comma from the resolved value of TESTSTR is followed by another comma in the argument of %QSCAN, i.e., the second argument of %QSCAN is actually a null string, which causes the warning message "Argument 2 ... is out of range" (see Kurt Bremser's post).
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.

acmilannesta
Calcite | Level 5

Thank you so mcuh, 

 

 

 

FreelanceReinh
Jade | Level 19

@acmilannesta wrote:

 

 

 


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.)

acmilannesta
Calcite | Level 5
I see. That's why I got a warning message telling me an unclosed parenthesis. Many thx!
Tom
Super User Tom
Super User

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, %
acmilannesta
Calcite | Level 5

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.

Tom
Super User Tom
Super User

@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%*'));
acmilannesta
Calcite | Level 5
Thank you, Tom!
Yes, the "dequote" function is really a nice way to bypass all these worries of macro symbols. Lesson learned!

Ready to join fellow brilliant minds for the SAS Hackathon?

Build your skills. Make connections. Enjoy creative freedom. Maybe change the world. Registration is now open through August 30th. Visit the SAS Hackathon homepage.

Register today!
Mastering the WHERE Clause in PROC SQL

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.

Discussion stats
  • 10 replies
  • 1658 views
  • 0 likes
  • 5 in conversation