Desktop productivity for business analysts and programmers

%LET %SYSFUNC and TRANWRD - Error (NOTE 49-169)

Accepted Solution Solved
Reply
Occasional Contributor
Posts: 6
Accepted Solution

%LET %SYSFUNC and TRANWRD - Error (NOTE 49-169)

Hello Community,

 

I am writing some program in SAS, where I would like to define a arbitrarily long list of parameters by a %LET statement:

%let Countries = US, DE, IT;

I would like to keep the definition of parameters as simple and convenient as possible, as later on different users will use this code ...

 

To handle the parameters later in the code, I basically need to things:

  1. A string like US_DE_IT for naming data sets.
  2. A string like 'US', 'DE', 'IT' to place it in a WHERE statement.

If possible, I would like to NOT do it via a macro but work with %LET and %SYSFUNC.

 

For point 1, I was able to do so via:

%let strCountries = %sysfunc(compress(%sysfunc(tranwrd(%quote(&Countries),%quote(,),_))));

et voilà:

%put &strCountries;
US_DE_IT

For point 2, my idea was to take &strCountries (US_DE_IT) and replace _ with ', ' and add a leading and trailing '. I think this should result in: 'US', 'DE', 'IT'...

 

Code for "in beween" ',' looks as follows:

%let listCountries = %sysfunc(tranwrd(&strCountries,_,', '));

If a run this a get an error, stating:

 

NOTE 49-169: The meaning of an identifier after a quoted string may change in a future SAS release.  Inserting white space between a quoted string and the succeeding identifier is recommended.

 

 

What do I need to do? Any suggestions how I could point 1 and 2 done?

 

Thank you!


Accepted Solutions
Solution
‎01-24-2017 07:50 AM
Esteemed Advisor
Posts: 6,721

Re: %LET %SYSFUNC and TRANWRD - Error (NOTE 49-169)

A NOTE is a note and not an error. This particular NOTE appears when a character follows immediately after a trailing single or double quote of a string literal. This is because such a character might carry special meaning, like in

"01jan2016"d

and new special meanings might be added by SAS in the future.

 

I suggest to do your string manipulation in a data _null_ step:

%let Countries = US, DE, IT;
data _null_;
length outstring1 outstring2 $20;
do i = 1 to countw("&countries",',');
  outstring1 = catx('_',trim(outstring1),strip(scan("&countries",i,',')));
  outstring2 = catx(',',trim(outstring2),"'"!!strip(scan("&countries",i,','))!!"'");
end;
call symput('strcountries',trim(outstring1));
call symput('listcountries',trim(outstring2));
run;
%put &strcountries;
%put &listcountries;
---------------------------------------------------------------------------------------------
Maxims of Maximally Efficient SAS Programmers

View solution in original post


All Replies
Solution
‎01-24-2017 07:50 AM
Esteemed Advisor
Posts: 6,721

Re: %LET %SYSFUNC and TRANWRD - Error (NOTE 49-169)

A NOTE is a note and not an error. This particular NOTE appears when a character follows immediately after a trailing single or double quote of a string literal. This is because such a character might carry special meaning, like in

"01jan2016"d

and new special meanings might be added by SAS in the future.

 

I suggest to do your string manipulation in a data _null_ step:

%let Countries = US, DE, IT;
data _null_;
length outstring1 outstring2 $20;
do i = 1 to countw("&countries",',');
  outstring1 = catx('_',trim(outstring1),strip(scan("&countries",i,',')));
  outstring2 = catx(',',trim(outstring2),"'"!!strip(scan("&countries",i,','))!!"'");
end;
call symput('strcountries',trim(outstring1));
call symput('listcountries',trim(outstring2));
run;
%put &strcountries;
%put &listcountries;
---------------------------------------------------------------------------------------------
Maxims of Maximally Efficient SAS Programmers
Occasional Contributor
Posts: 6

Re: %LET %SYSFUNC and TRANWRD - Error (NOTE 49-169)

Thank you very much. Works perfect. Some new commands for me, so it really helps me. :-)

 

BTW: How have you been able to make your code look like in SAS?

 

Regards!

Esteemed Advisor
Posts: 6,721

Re: %LET %SYSFUNC and TRANWRD - Error (NOTE 49-169)

Use the "little running man" icon to open an editor window where the editor formats the code quite like the enhanced editor in SAS (after posting).

 

I usually use the data step technique to compose macro variables to avoid complicated sequences of %sysfunc's and quoting/unquoting functions.

TBH, I have no clue when to use the quoting functions. Never need them in a data step.

---------------------------------------------------------------------------------------------
Maxims of Maximally Efficient SAS Programmers
Esteemed Advisor
Esteemed Advisor
Posts: 7,253

Re: %LET %SYSFUNC and TRANWRD - Error (NOTE 49-169)

Sounds like a total faff to me.  Putting lists in macro variables is never the best way to do things but will make you write spaghetti code to handle it.  What exactly is it your trying to do?  If you need to loop of a set of data (clues in the title here) then put your data in a dataset, then use that to roll off the other code, either macro or generated.  Eg.

data _null_;
  set listofcountrycodes;
  call execute(cats('%macro DoSomething (country=',country,');');
run;
Occasional Contributor
Posts: 6

Re: %LET %SYSFUNC and TRANWRD - Error (NOTE 49-169)

Thanks for your input. I am very happy with the solution KurtBremser provided.

 

For my program, users should be able to easily and fast change the list of countries. The %LET statement is the most convenient way I could think of.

 

 

Grand Advisor
Posts: 10,251

Re: %LET %SYSFUNC and TRANWRD - Error (NOTE 49-169)

Please be aware that when you use a macro variable with commas such as your %let Country = US, IT, DE; that if you attempt to use that as a parameter for a macro you are almost always going to get either unexpected results or an error of "more positional parameters than declared" type error.

Super User
Super User
Posts: 6,383

Re: %LET %SYSFUNC and TRANWRD - Error (NOTE 49-169)

[ Edited ]

If your values are simple country codes like in your example (that is no embedded commas or spaces in the individual item values) I would recommend telling the users to NOT enter any commas.  But that might be difficult to enforce so you might see values like this in the user generated %LET statements.

%let Countries = US,   DE,   IT;
%let Countries = US DE IT;
%let Countries = us, De  IT;

You can convert that to a simple space delimited list using code like:

%let cleanCountries=%sysfunc(compbl(%sysfunc(translate(%qupcase(&countries),' ',','))));

This will fix the case, remove the commas and compress multiple spaces to just one. Note there is no need to macro quote the space or comma if they are inside of quotes. Translate will just convert any quotes it sees back to quotes since it matches the lists of characters convert element by element.

 

You can then convert that to your underscore delimited version:

%let listCountries=%sysfunc(translate(&cleanCountries,'_',' '));

You can also use your tranwrd method to convert to a list of quoted values.

%let strCountries=%unquote(%bquote('%qsysfunc(tranwrd(&listCountries,_,' '))'));

You could use commas instead of spaces between the quoted strings if you want, but note that SAS is happy to use the space delimited list instead of comma delimited list.  For example when using the IN operator.

where countryCode in ('US' 'DE' 'IT');

 

☑ This topic is SOLVED.

Need further help from the community? Please ask a new question.

Discussion stats
  • 7 replies
  • 344 views
  • 1 like
  • 5 in conversation