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.
Join us for SAS Innovate April 16-19 at the Aria in Las Vegas. Bring the team and save big with our group pricing for a limited time only.
Pre-conference courses and tutorials are filling up fast and are always a sellout. Register today to reserve your seat.
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.