Reputation: 1120
Assume we have a macro variable:
%let letters = a b c d e f g h i j;
First, I want to remove the last letter from the macro variable and assign the remaining letters to a new macro variable. Second, I want to remove any given letter from the macro variable and assign the remaining letters to a new macro variable. I have written two macros that do these things but was wondering if there is a better way of going about them. Most other programming languages have add/remove functions for this sort of thing, but it seems that SAS does not - is this accurate?
First macro:
%macro remove_last_letter(macro_var);
%let letters_no_last = ;
%do i = 1 %to %sysfunc(countw(&&¯o_var..))-1;
%let this_letter = %scan(&&¯o_var.., &i.);
%let letters_no_last = &letters_no_last. &this_letter.;
%end;
%put &letters_no_last.;
%mend remove_last_letter;
%remove_last_letter(letters);
yields:
a b c d e f g h i
Second macro:
%macro remove_a_letter(macro_var, letter_to_remove);
%let letters_no_spec = ;
%do i = 1 %to %sysfunc(countw(&&¯o_var..));
%let this_letter = %scan(&&¯o_var.., &i.);
%if &this_letter. ~= &letter_to_remove. %then %do;
%let letters_no_spec = &letters_no_spec. &this_letter.;
%end;
%end;
%put &letters_no_spec.;
%mend remove_a_letter;
%remove_a_letter(letters, c);
yields:
a b d e f g h i j
Upvotes: 0
Views: 3009
Reputation: 51621
Looks like you want to remove words and not letters. Also your macros will probably be more useful if you code them so that they can work as macro functions.
To remove the last word you just need to know how long it is. You do not need to return anything if the list doesn't have at least two words.
%macro remove_last_word(list);
%if %sysfunc(countw(&list,%str( ))) > 1 %then
%substr(&list,1,%length(&list)-%length(%scan(&list,-1,%str( ))))
;
%mend remove_last_word;
%put %remove_last_word(a b c d);
If you want to remove all occurrences of a word then the TRANWRD()
function is good for that. Make sure to add leading and trailing delimiters to both the list and the word so that it does not match part of a longer word in the list.
%macro remove_word(list,word);
%sysfunc(tranwrd(%bquote( &list ),%bquote( &word ),%str( )))
%mend remove_word;
%put %remove_word(a b c d,c);
Upvotes: 1
Reputation: 63434
The SAS macro language isn't really a fully featured language. As such, no, it wasn't really designed to store lists the way we use it in the modern day. I don't really think it's common for other languages to have dedicated functions for removing specific words from strings, which is what you have here; but in SAS it's not particularly hard.
The first one I think if you are using single letters, it's trivial.
%macro remove_last_letter(macro_var);
%put %substr(¯o_var.,1,%length(¯o_var.)-1);
%mend remove_last_letter;
If it's more than one character long of course you need to figure out how long the last one is, but you can use %sysfunc(countw())
to identify the word and find out how long it is - or you can find the last space in the string and use that to remove it, which might be easier:
%macro remove_last_word(macro_var);
%let lastspacepos = %sysfunc(find(¯o_var.,%str( ),1-%length(¯o_var.)));
%put &=lastspacepos.;
%put %substr(¯o_var.,1,&lastspacepos.);
%mend remove_last_word;
%remove_last_word(abc def ghi jkl mno);
For your second part, I think TRANWRD is the way to go.
%macro remove_a_letter(macro_var, letter_to_remove);
%put %sysfunc(tranwrd(¯o_var.,%str( )&letter_to_remove%str( ),%str( )));
%mend remove_a_letter;
%remove_a_letter(a b c d e f g h i j,c);
It will of course remove every c
in the string, not just one, but it seems like you'd want that by your specification.
TRANWRD solution could also be used for the first version, by using SCAN with a -1 parameter for which word to grab (the rightmost word) and then TRANWRD that to blank, if you knew it was a unique character.
Upvotes: 2