Search code examples
compiler-errorssasmacrossas-macro

Using part of a keyword to extract a full keyword in SAS


In my project i am taking a users input and one of the variables is key to extract. This variable is year but may be written for some datasets as say "Graduation_year" where in others it may be say "Year_of_purchase" and so on. What i need to do is take this variable out of a list to be used separately from the remainder of the list. From the example below what my desired outcome looks like is as follows: Input -> (Gender Graduation_Year Course_Name) Outputs -> Var_of_importance = Graduation_year and Remainder_vars= Gender Course_name.

The code i am using so far has come across an error as i'm trying to update a macro variable at each iteration of the second loop called size.

The code is as follows:

%macro Year_finder(var_list);

%local size;
%Put The variables are: &var_list.;
%let Keyword_loc=%Index(&var_list.,Year);

%put The location of the keyword Year begins at place number &Keyword_loc.;

%do i=1 %to %sysfunc(countw(&var_list.));
    %let word_&i.=%length(%sysfunc(scan(&var_list.,&i.)));
    %put The length of %sysfunc(scan(&var_list.,&i.)) is &&word_&i.;
%end;

%do i=1 %to %sysfunc(countw(&var_list.));
    
    %if i=1 %then %do;
        %if &&word_&i. LT &Keyword_loc. and &&word_(&i.+1)+1 GT &Keyword_loc. %then Word = %sysfunc(scan(&var_list.,&i.));
        %let size=&&word_&i.;

        %put The step number is step &i.;
        %put The &i.th word has a length of &&word_&i.;
        %put Initial length is &size.;
    %end;
    
    %else %do;
        %eval(&size. = &size.+ &&word_&i. + 1);
        %if &size. LT &Keyword_loc. and &size. + &&word_(&i.+1) + 1 GT &Keyword_loc. %then Word = %sysfunc(scan(&var_list.,(&i.+1)))

        %put This step number is step &i.;
        %put The length variable = &size.;
        %put The word is &Word.;
    %end;
%end;

%mend;

%Year_finder(Gender Graduation_Year Course_Name);

At the moment this seems like it will do what i want it to but as i cant get past this error i cannot verify it works. Any help would be greatly appreciated. Thank you.


Solution

  • To solve your problem, the easiest is to check if each word individually contain "year" and add them to the desired output macro variable. The following should work:

    %macro Year_finder(var_list);
    
       * Initialize output variables;
       %global Var_of_importance Remainder_vars;
       %let Var_of_importance = ;
       %let Remainder_vars = ; 
    
       * Go through words from var_list;
       %do i=1 %to %sysfunc(countw(&var_list.));
          * Add word to var_of_importance if it contain "year" (not case sensitive);
          %if %index(%lowcase(%scan(&var_list.,&i.)),year) %then %do;
             %let Var_of_importance = &Var_of_importance %scan(&var_list.,&i.);
          %end;
          %else %do;
             * Add word to Remainder_vars if it does not contain "year";
             %let Remainder_vars = &Remainder_vars %scan(&var_list.,&i.);
          %end;
       %end;
    
    %mend;
    
    %Year_finder(Gender Graduation_Year Course_Name);
    

    Your original code has several problems

    • You never mention the variables Var_of_importance or Remainder_vars that are your end goal. Note that these should be global variables.
    • You miss an ampersand in your first if statement. Change %if i=1 %then %do; to %if &i=1 %then %do;
    • In your next if statements miss a %sysevalf() to evaluate the complicated expression and you miss a %let in your %then word =
    • If you want to refer to the next index you cannot write &&word_(&i.+1). Instead you can write %superq(word_%eval(&i+1)). For details see Resolving macro containing %eval in macro variable name, SAS
    • You keep comparing the lengths of each word (&&word_&i.) to the location of "year" (&Keyword_loc.). However, you should compare the accumulated length, which you call size
    • You have a eval function without any other statements, as noted by Tom in another answer. You probably wanted to write %let size = %eval(&size.+ &&word_&i. + 1);