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

When I use the following in a macro, I get an ERROR: message:

 

3    %let list1 = a b ;
4    %let list2 = b c ;
5
6    %let list = "%sysfunc( prxchange( s/\s+/%str(" , ")/ , -1 , %nrbquote(&list1. &list2.)))" ;
7    %put &list. ;
"a" , "b" , "b" , "c"
8
9
10
11   %macro tmp ;
12
13                    data __dedup ;
14                      do var = "%sysfunc( prxchange( s/\s+/%str(" , ")/ , -1 , %nrbquote(&list1.
14 !  &list2.)))" ;
ERROR: Expected close parenthesis after macro function invocation not found.
15                        if var ne " " then output ;
16                      end ;
17                    run ;
18   %mend ;
19
20
21   %tmp ;
ERROR: Expected close parenthesis after macro function invocation not found.

NOTE: The SAS System stopped processing this step because of errors.
WARNING: The data set WORK.__DEDUP may be incomplete.  When this step was stopped there were 0
         observations and 1 variables.
NOTE: DATA statement used (Total process time):
      real time           0.01 seconds
      cpu time            0.01 seconds

I would appreciate any insight, references, or solutions.  Note that I remove single and double quotation marks in a prior step.  We are using "traditional" SAS variable names only, but that will make an interesting challenge to address.

 

Thank you,

 

Kevin

1 ACCEPTED SOLUTION

Accepted Solutions
Tom
Super User Tom
Super User

The error message is pretty straight forward. It is from SYSFUNC saying it did not see the double right parentheses you normally need in a expression like 

%sysfunc(sasfunc())

So why does it work in open code and fail in macro code?

Let's look at your %sysfunc() call:

"%sysfunc( prxchange( s/\s+/%str(" , ")/ , -1 , %nrbquote(&list1.    &list2.)))" 

The issue is that inside a macro the parsing is getting confused by have the quotes macro quoted.  So just remove those.  You only need to quote the comma.

"%sysfunc( prxchange( s/\s+/" %str(,) "/ , -1 , %nrbquote(&list1.    &list2.)))" ;

If you do want to use %STR() to macro quote the quotes then add % in front of each.

"%sysfunc( prxchange( s/\s+/%str(%" , %")/ , -1 , %nrbquote(&list1.    &list2.)))" 

Or use BQUOTE().  Also I am not sure why you are using NRBQUOTE() in the other place.

"%sysfunc( prxchange( s/\s+/%bquote(" , ")/ , -1 , %bquote(&list1.    &list2.)))" 

If you want to keep the issue in macro code then just make some deduping logic of your own.

%macro dedupvars(varlist);
%local newlist i newvar;
%do i=1 %to %sysfunc(countw(&varlist,%str( )));
  %let newvar=%scan(&varlist,&i,%str( ));
  %if not %sysfunc(indexw(%upcase(&newlist),%upcase(&newvar))) %then
    %let newlist=&newlist &newvar
  ;
%end;
&newlist.
%mend dedupvars;
%put %dedupvars(A b c a B C e);

View solution in original post

4 REPLIES 4
ballardw
Super User

What I strongly suspect is happening is that the DO  will accept character values in a list:

data example;
   do var= "A","B","X";
      output;
   end;
run;

So your

 do var = "%sysfunc( prxchange( s/\s+/%str(" , ")/ , -1 , %nrbquote(&list1.
14 !  &list2.)))" ;

is two pieces of text:

"%sysfunc( prxchange( s/\s+/%str("

and

")/ , -1 , %nrbquote(&list1.&list2.)))"

So the 'functions' aren't closed /opened properly.

 

I can't tell what you are attempting to provide an alternate but question the need for the %str, or at least why it is there.

Kevin_Viel
Obsidian | Level 7

Thank you for the response.

 

Consider this:

 

4229  %let list1 = a b ;
4230  %let list2 = b c ;
4231
4232  data __dedup ;
4233    do var = "%sysfunc( prxchange( s/\s+/%str(" , ")/ , -1 , %nrbquote(&list1. &list2.)))" ;
4234      if var ne " " then put var= ;
4235    end ;
4236  run ;

var=a
var=b
var=b
var=c
NOTE: The data set WORK.__DEDUP has 1 observations and 1 variables.
NOTE: DATA statement used (Total process time):
      real time           0.01 seconds
      cpu time            0.00 seconds

I am taking a list of SAS variables and quoting them and placing commas between them.  A B will be "A" , "B".  I already removed possible quotation marks (single and double) and commas.  I need to mask the comma in the regex, so I used the %STR() function.  I am protecting against a user submitting the same variable in both lists, so I de-dup it.  I figured the SQL (or SORT) procedure has a trusted way, so I needed to put the variables as values of a variable in a SAS data set. This seemed like an obvious approach.  This must be an issue with the macro compiler, since it works fine above.

 

 

If I were to use SAS code and not macro, then the quotation mark would "protect" the comma:

 

4344  data __dedup ;
4345    var = prxchange( 's/\s+/" , "/'
4346                   , -1
4347                   , "A B"
4348                   ) ;
4349    put var= ;
4350  run ;

var=A" , "B
NOTE: The data set WORK.__DEDUP has 1 observations and 1 variables.
NOTE: DATA statement used (Total process time):
      real time           0.01 seconds
      cpu time            0.00 seconds

 

This, also, was perplexing (at least from my level of understanding):

 

 

4250  %let list1 = %sysfunc( prxchange( s/\s+/%str(" , ")/ , -1 , %nrbquote(&list1.))) ;
4251  %put &list1. ;
a" , "b
4252
4253  %let list2 = %sysfunc( prxchange( s/\s+/%str(" , ")/ , -1 , %nrbquote(&list2.))) ;
NOTE: Line generated by the macro function "SYSFUNC".
1      b" , "c
        -----
        49
NOTE 49-169: The meaning of an identifier after a quoted string might change in a future SAS release.  Inserting white space
             between a quoted string and the succeeding identifier is recommended.

4254  %put &list2. ;
NOTE: Line generated by the macro variable "LIST2".
1      b" , "c
        -----
        49
b" , "c
NOTE 49-169: The meaning of an identifier after a quoted string might change in a future SAS release.  Inserting white space
             between a quoted string and the succeeding identifier is recommended.

Specifically, white space follows the double quotation mark; I purposefully inserted it.  Quizzically, the first statement does not generate the code.

 

 

Kind regards,

 

Kevin

Tom
Super User Tom
Super User

The error message is pretty straight forward. It is from SYSFUNC saying it did not see the double right parentheses you normally need in a expression like 

%sysfunc(sasfunc())

So why does it work in open code and fail in macro code?

Let's look at your %sysfunc() call:

"%sysfunc( prxchange( s/\s+/%str(" , ")/ , -1 , %nrbquote(&list1.    &list2.)))" 

The issue is that inside a macro the parsing is getting confused by have the quotes macro quoted.  So just remove those.  You only need to quote the comma.

"%sysfunc( prxchange( s/\s+/" %str(,) "/ , -1 , %nrbquote(&list1.    &list2.)))" ;

If you do want to use %STR() to macro quote the quotes then add % in front of each.

"%sysfunc( prxchange( s/\s+/%str(%" , %")/ , -1 , %nrbquote(&list1.    &list2.)))" 

Or use BQUOTE().  Also I am not sure why you are using NRBQUOTE() in the other place.

"%sysfunc( prxchange( s/\s+/%bquote(" , ")/ , -1 , %bquote(&list1.    &list2.)))" 

If you want to keep the issue in macro code then just make some deduping logic of your own.

%macro dedupvars(varlist);
%local newlist i newvar;
%do i=1 %to %sysfunc(countw(&varlist,%str( )));
  %let newvar=%scan(&varlist,&i,%str( ));
  %if not %sysfunc(indexw(%upcase(&newlist),%upcase(&newvar))) %then
    %let newlist=&newlist &newvar
  ;
%end;
&newlist.
%mend dedupvars;
%put %dedupvars(A b c a B C e);
Kevin_Viel
Obsidian | Level 7

Tom,

 

  As usual, an excellent reply with plenty of educational points.  With more than 20 years of doing it, being wrong on the internet about SAS still stings 🙂

 

  I violated one of my rules: mask nothing more than required.

 

  I think that I used %NRBQUOTE() out of habit of quoting strings that might have, by bad practice, certain tokens, like % or &, even if the values might not be valid (I might have a error check for well-formed values at the beginning of a macro, but I carry it through).  Also, I read Ian Whitlock's quoting papers (and posts) periodically, but I should probably read them again.

 

  I like the elegance of your wholly macro approach to dedup the list.

 

Thank you,

 

Kevin

  

SAS Innovate 2025: Register Now

Registration is now open for SAS Innovate 2025 , our biggest and most exciting global event of the year! Join us in Orlando, FL, May 6-9.
Sign up by Dec. 31 to get the 2024 rate of just $495.
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.

SAS Training: Just a Click Away

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

Browse our catalog!

Discussion stats
  • 4 replies
  • 1597 views
  • 1 like
  • 3 in conversation