After removing the %str from the below code it will not work and my values is coming from a call symput macro variable.Kindly help me how to resolve the same. I want to use it as ----> %let string=a,123;b,321;c,456;d,789;e,888;
%global string;
%let string=%str(a,123;b,321;c,456;d,789;e,888);
%put "&string.";
options mprint mlogic symbolgen;
%macro test;
%let word_cnt = %eval(%sysfunc(countc("&string.",';'))+1);/* Problem in this line */
%let count= &word_cnt;
%put &word_cnt.; */
%do i = 1 %to &word_cnt.;
%let var&i=%sysfunc(trim(%qscan(&string.,&i,%str(';')))); /* Problem in this line...rest every thing is fine */
%put &&var&i;
%end;
%do j=1 %to 5;
%let dataset_key&j= %scan(%quote(&&var&j),1,%str(","));
%let dataset_Name&j= %scan(%quote(&&var&j),2,%str(","));
%put &&dataset_key&j;
%put &&dataset_Name&j;
%end;
% put &string;
%mend test;
%test;
Don't make us do work you have already done. SHOW US THE SASLOG (and put the options mprint mlogic symbolgen; statement at the top of your code)
%macro test;
%let word_cnt = %eval(%sysfunc(countw(&string,%str(;)))+1);/* Problem in this line */
%let count= &word_cnt;
%put &word_cnt.;
%do i = 1 %to &word_cnt.;
%let var&i=%sysfunc(trim(%qscan(&string,&i,%str(;)))); /* Problem in this line...rest every thing is fine */
%put &&var&i;
%end;
%do j=1 %to 5;
%let dataset_key&j= %scan(%quote(&&var&j),1,%str(,));
%let dataset_Name&j= %scan(%quote(&&var&j),2,%str(,));
%put &&dataset_key&j;
%put &&dataset_Name&j;
%end;
%put &string;
%mend test;
%test
And just what is the problem?
For one thing
%let string=a,123;b,321;c,456;d,789;e,888;
The definition of string ends at the first semicolon as the end of the %let statement. Almost any time the delimiters , or ; are used you are causing your one problems. So why do you have them? I do not see any use for of &string that requires the delimiters.
If you have paired values it might be better to have two space delimited lists instead of a complex
%macro dummy; %let vstring=a b c d e ; %let nstring= 123 321 456 789 888; %let word_cnt = %sysfunc(countw(&vstring)); %put word_cnt= &word_cnt; %do i=1 %to &word_cnt; %let var&i = %scan(&vstring,&i); %let num&i = %scan(&nstring,&i); %put var&i= &&var&i; %put num&i= &&num&i; %end; %mend; %dummy;
There is some strange interaction between using %SYSFUNC() in a complex statement inside of a macro and your delimiters.
For example this code works fine outside of a macro.
data _null_;
call symputx('string','a,123;b,321;c,456;d,789;e,888');
run;
%let string=%superq(string);
%put &=string;
%put Nwords = %sysfunc(countw(&string,%str(;)));
Or even inside a macro:
data _null_;
call symputx('string','a,123;b,321;c,456;d,789;e,888');
run;
%macro test;
%let string=%superq(string);
%put &=string;
%put Nwords = %sysfunc(countw(&string,%str(;)));
%mend test;
%test;
But try to use that SYSFUNC() call in a %DO statement and it bombs.
%macro test;
%local i;
%let string=%superq(string);
%do i=1 %to %sysfunc(countw(&string,%str(;)));
%put &=i ;
%end;
%mend test;
%test;
1655 %test; ERROR: Expected close parenthesis after macro function invocation not found. NOTE: One or more missing close parentheses have been supplied for the %COUNTW function. ERROR: Expected close parenthesis after macro function invocation not found. ERROR: %EVAL function has no expression to evaluate, or %IF statement has no condition. ERROR: The %TO value of the %DO I loop is invalid. ERROR: The macro TEST will stop executing.
But if you just assign the count to a macro variable all is well again.
%macro test;
%local i n;
%let string=%superq(string);
%let n= %sysfunc(countw(&string,%str(;)));
%do i=1 %to &n;
%put &=i ;
%end;
%mend test;
%test;
And it works fine
1664 %test; I=1 I=2 I=3 I=4 I=5
You have other problems with your macro.
You are including quotes in the arguments to the %SCAN() function which is going to cause issues. the %SCAN() function treats all of the characters you give it as delimiters. So if your string includes quotes and you tell %scan() that the delimiters are quote, semi-colon (and redundantly quote again) then you might not parse the string properly.
The logic of it seems strange. Why are you making a series of macro variables? Why not just use the value as you derive it?
%macro test;
%local i n word dataset_key dataset_name ;
%let string=%superq(string);
%let n= %sysfunc(countw(&string,%str(;)));
%do i = 1 %to &n;
%let word=%qscan(&string,&i,%str(;));
%let dataset_key = %scan(&word,1,%str(,));
%let dataset_name = %scan(&word,2,%str(,));
%put &=i &=word &=dataset_key &=dataset_name ;
%end;
%mend ;
1731 data _null_; 1732 call symputx('string','a,123;b,321;c,456;d,789;e,888'); 1733 run; 1734 %test; I=1 WORD=a,123 DATASET_KEY=a DATASET_NAME=123 I=2 WORD=b,321 DATASET_KEY=b DATASET_NAME=321 I=3 WORD=c,456 DATASET_KEY=c DATASET_NAME=456 I=4 WORD=d,789 DATASET_KEY=d DATASET_NAME=789 I=5 WORD=e,888 DATASET_KEY=e DATASET_NAME=888
Thanks a ton it works for me.
I like @Tom's solution to the problem as you presented it. His response is a nice demonstration of the usefulness of the SUPERQ macro function.
But why use a semi-colon as a group delimiter in the first place? Yes, you can make two lists as @ballardw suggested, but you could also chose a delimiter like !, as in
%let string = a,123!b,321!c,456!d,789!e,888;
This would allow you to drop the %STR usage, and the rest of your code logic would need no changes except for specifying ! as the group delimiter. Just choose a delimiter that you know will not be part of the string value, and does not need masking by %STR.
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!
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.