Reputation: 113
I am trying to get the values passed in a macro variable and put quotes around it. i.e. space separated list to space separated quoted list. e.g. given below. I have used the following approach given by Jeff in one of my earlier post.
data test;
id =1; _var="ABC"; output;
id =1; _var="DEF"; output;
id =1; _var="UVW"; output;
id =2; _var="UVW"; output;
id =3; _var="ABC"; output;
id =3; _var="UVW"; output;
id =3; _var="XYZ"; output;
id =4; _var="ABC"; output;
id =4; _var="XYZ"; output;
run;
%macro __test1(_byvar=, _qnam=, _id=);
proc sort data= test out=_test;
by &_byvar.;
%if %superq(_qnam) ne %then
%do;
%let __tmpmv_qnam = %qsysfunc(prxchange(%bquote(s/\b/"/),-1,%bquote(&_qnam)));
*";
%put ^^^^^&__tmpmv_qnam.;
where upcase(&_id) in (&__tmpmv_qnam);
%end;
run;
%mend;
%__test1 (_byvar=id ,_qnam = ABC UVW, _id=_var);
The log diaplayed following error:
SYMBOLGEN: Macro variable _QNAM resolves to ABC UVW
ERROR: Literal contains unmatched quote.
Please help on this one.
Upvotes: 2
Views: 9652
Reputation: 51566
You seem to be making the problem harder than it is. Why not just use the INDEXW()
function?
where indexw(symget('_qnam'),upcase(&_id),' ');
Or if you want to convert ABC UVW
to "ABC","UVW"
then a simple TRANWRD()
function call will do.
where upcase(&_id) in ("%sysfunc(tranwrd(&_qnam,%str( ),","))");
However if your list could have extra spaces, if it was typed by hand for example, you will want to first remove the extra spaces.
%let _qnam=%sysfunc(compbl(&_qnam));
Upvotes: 0
Reputation: 8513
You can have an unmatched quote within a macro by using the %str()
function like so:
%str(%') <-- gives an unmatched single quote
%str(%") <-- gives an unmatched double quote
I've applied this to your macro and reorganized/simplified it a little. Firstly you'll see that I've removed redundant %bquote()
functions and changed %qsysfunc()
to just %sysfunc()
.
I'm also building the string for the where clause and saving it to a macro variable so that the sort statement stands out more and the result of the where clause is easier to debug.
%macro __test1(_byvar=, _qnam=, _id=);
%local list where_clause;
%if %length(_qnam) gt 0 %then%do;
%let list = %sysfunc(prxchange(s/\b/%str(%")/,-1,&_qnam));
%let where_clause = where upcase(&_id) in (&list);
%end;
proc sort data= test out=_test;
by &_byvar.;
&where_clause;
run;
%mend;
Upvotes: 0
Reputation: 9569
Here's an alternative approach to adding the quotes. It's pretty basic - it doesn't check whether the input is already quoted, and there must be exactly 1 space between list items, and there must be no leading or trailing spaces in the input list, but you can adapt it to suit your needs:
%let list = a b c;
%macro qlist(LIST);
%sysfunc(compbl(
%do i = 1 %to %eval(%sysfunc(count(&LIST, %str( ))) + 1);
"%scan(&LIST,&i)" %str( )
%end;
))
%mend qlist;
%put %qlist(&list);
Upvotes: 2