Colon modifier in macro - sas

I'm trying to use the colon modifier functionality in a macro but it doesn't seem to work the same way as in a data step. An example of what I'm trying to do is shown below.
data _null_;
str = "hello";
if str =: "h" then put "y";
else put "n";
run;
The if-statement evaluates TRUE in the data step but when I apply similar logic in the macro language this no longer appears to work.
%let str = hello;
%put %eval(&str =: h);
The code above now evaluates to FALSE. Is there something I'm missing here or is this modifier just not available in the macro language? I know I could use %eval(%substr(&str,1,1)=h) but I'm more curious to find out if the : will work.

No, the : is not in the list of macro operators; see the macro language reference for more details.
Note that =: is also not valid in other places, such as in PROC SQL. In those contexts eqt is the equivalent operator, but that also does not work in the macro language.

Related

SAS: Delete missing items in a macro variable

I have a macro variable called list1, which gives:
%put &list1.;
A,B,C,D,,,G,,I,,
I need to delete those items which are missing i.e empty between the commas. The final output should be like A,B,C,D,G,I. Is it possible? Trim function does not seem to work here. I'm new to SAS so any help will be appreciated here. Thanks.
%let a= A,B,C,D,,,G,,I,,;
data c;
val = tranwrd(trim(compbl(tranwrd("&a",","," "))), " ",",");
call symput('b',val);
run;
%put &b;
This result of A,B,C,D,G,I
Just for fun - pure macro regex version:
%let a= A,B,C,D,,,G,,I,,;
%let regex1 = %sysfunc(prxparse(%str(s/,+/,/)));
%let b=%sysfunc(prxchange(&regex1,-1,%quote(&a)));
%let regex2 = %sysfunc(prxparse(%str(s/,$//)));
%let b=%sysfunc(prxchange(&regex2,-1,%quote(&b)));
%put b= &b;
You can skip the second regex if you never have to deal with trailing commas at the end of your input.
You could convert the commas to spaces and use COMPBL() to collapse the multiple spaces. Then convert the spaces back into commas. In case you have any spaces just swap the comma and the space characters.
%let temp=%sysfunc(translate(%superq(list1),%str( ,),%str(, )));
%let temp=%sysfunc(compbl(%superq(temp)));
%let list2=%sysfunc(translate(%superq(temp),%str( ,),%str(, )));
PS You don't normally want to use comma as the delimiter in macro variables. It makes it difficult to pass the value to other macros or functions since comma is used to separate argument values. Hence all of the macro quoting functions in this code. For variable lists you would normally want a space delimited list where multiple adjacent spaces wouldn't matter. For other types of lists you would normally want another delimiter like | or ^.

Tranwrd just one letter in SAS

How can i quote just one letter in sas?
%sysfunc(tranwrd(%quote(&string),%quote(T),%quote('Test')));
The Problem is, when the string has a 'T' and 'TR' that both get tranwrd to 'Test'
SAS Macro variables are always character. The arguments to macro functions are always character and generally won't require an extra layer of macro macro quoting, and definitely won't if the arguments are to be as literals.
Did you try this first ?
%let string = STACKOVERFLOW;
%let string_tweaked = %sysfunc(tranwrd(&string),T,Test);
%put NOTE: string_tweaked = &string_tweaked;
Do the macro values contain embedded single quotes ?
%let string = %str(S%'T%'ACKOVERFLOW);
%let string_tweaked = %qsysfunc(tranwrd(&string,'T','Test'));
%put NOTE: string_tweaked = &string_tweaked;
The second code sample is analogous to the following DATA step code (whose scope is different than that of the MACRO environment). DATA step string values are explicitly quoted, with either double quote (") or single quote (')
data _null_;
string = "S'T'ACKOVERFLOW";
string_tweaked = tranwrd(string,"'T'","'Test'");
put "NOTE: " string_tweaked=;
run;

what the last "." after the macro variable mean

Below is the code to create the dataset from exisitng datasets, where end and end8, end7 are macro variables, just wondering why add . at the end of the macro variables?
data tab4a_&end.;
set
mck_tab4a_&end8.
mck_raw.mck_tab4a_&end7.
run;
The dot marks the end of the macro variable. It is often used when macro text is combined with static text, e.g. in a filename, so that SAS knows where the macro variable ends. E.g.:
%let year=2017;
%let filename = &year._accounts.xlsx;
%put &filename;
Produces 2017_accounts.xlsx
Without the first dot, SAS will produce a warning message, because it will be looking for a macro variable called year_accounts. (It can't tell where the macro ends and the text starts).
If there is a space or an end of statement after the macro variable then the dot can be omitted. Including the dot has no effect in this case. Some people think it is good to always include the dot.
It's used to denote the end of a macro variable. This is important when you're mixing macro variables and text.
For example:
%let my_var = TEST;
%let my_var_new = WRONG;
%put &my_var._new;
%put &my_var_new.;
OUTPUT:
58 %let my_var = TEST;
59 %let my_var_new = WRONG;
60 %put &my_var._new;
TEST_new
61 %put &my_var_new.;
WRONG
How does the macro processor know if the macro variable is my_var or my_var_new? The period tells SAS where the macro variable ends.
Including the dot also turns the macro variable green in the editor which helps for reading and debugging code.

Append extra characters after a macro variable in SAS?

I have a simple macro where I am passing in a parameter but also want to append onto the macro. However, when I try to add the additional text it won't recognize the original macro variable. I have tried to convert the macro variable to a string first, append the extra text, then unquote it but can't find an appropriate concatenate function to use.
Here is my macro and what isn't working now, with the problem being &del_30 in the third line. The compiler is trying to interpret &del_30 as a macro, instead of &del_ by itself.
%macro plot_better_same_worse(title_, del_);
proc Sgplot data=ALL_TP_NORM_TBL;
SERIES X = asofdt Y = &del_30 /
MARKERS LINEATTRS = (THICKNESS = 2);
run;
%mend plot_better_same_worse;
I have also tried to do this instead: &&del_&30 but SAS tries to interpret &30 as a macro variable as well.
Macro variable names begin with & and end with ., or the first character illegal to be in a macro variable name (A-Z, 0-9, _).
So &del_.30 would resolve &del_ and then put 30 after it.

One function to replace different text with other in SAS

I want to replace one combination of text with another. For example
data test;
a='raja\ram{work}italic';
if index(a,'\') then b=tranwrd(a,'\','\\');
if index(a,'{') then b=tranwrd(a,'{','\{');
if index(a,'}') then b=tranwrd(a,'}','\}');
if index(upcase(a),'ITALIC') then b=tranwrd(a,substr(a,index(upcase(a),'ITALIC'),length('ITALIC')),'\i');
run;
Required Result: b=raja\\ram\{work\}\i;
These kind of combination I wanted to replace. I'm not interested to use a macro or FCMP or if else condition.
Is there any function to do all at once? I tried to use a Perl expression that also working for one at a time b= prxchange('s/\\/\\\\/', -1, a)
Your regular expression is on the right track. You have a set of characters, right, you want to always prepend a \ to? So search for (one of that set of characters), which you do with [...], and then add a \ to it, using a capturing group. That's the escape character, so you have to add two any time you want to use one (\\ escapes itself to \).
data test;
a='Hello\Goodbye{stuff}';
b= prxchange('s/([\\{}])/\\$1/',-1,a);
put b=;
run;
You should do the italic bit in a second expression (or just use tranwrd). That's a totally different replacement and while theoretically possible to put in one, would make it too messy.
This question is almost identical to the other question: Multiple search and replace within a string through regular expression in SAS
Is that a coincidence?
Here is the code that worked for the other question.
%let text = abc\pqr{work};
data _null_;
var=prxchange("s/\\/\\\\/",-1,"&text");
var=prxchange("s/\{/\\\{/",-1,var);
var=prxchange("s/\}/\\\}/",-1,var);
put var;
run;
Result: abc\\pqr\{work\};
%let text = BOLD\ITALIC\ITALICBOLD\BOLDITALIC\B\I\IB\BI;
data _null_;
var=prxchange("s/BOLD/b/",-1,"&text");
var=prxchange("s/ITALIC/i/",-1,var);
var=lowcase(var);
put var;
run;
RESULT: b\i\ib\bi\b\i\ib\bi