BookmarkSubscribeRSS Feed
ankitk321
Fluorite | Level 6

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;

 

6 REPLIES 6
PaigeMiller
Diamond | Level 26

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)

--
Paige Miller
novinosrin
Tourmaline | Level 20
%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
ballardw
Super User

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;
Tom
Super User Tom
Super User

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
ankitk321
Fluorite | Level 6

Thanks a ton it works for me.

mkeintz
PROC Star

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.

--------------------------
The hash OUTPUT method will overwrite a SAS data set, but not append. That can be costly. Consider voting for Add a HASH object method which would append a hash object to an existing SAS data set

Would enabling PROC SORT to simultaneously output multiple datasets be useful? Then vote for
Allow PROC SORT to output multiple datasets

--------------------------

hackathon24-white-horiz.png

2025 SAS Hackathon: There is still time!

Good news: We've extended SAS Hackathon registration until Sept. 12, so you still have time to be part of our biggest event yet – our five-year anniversary!

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
  • 6 replies
  • 1826 views
  • 3 likes
  • 6 in conversation