BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
CHELS
Obsidian | Level 7

I am trying to create a macro that change some words in a sting to lower case. However, only the first word in the list 'Or' was being changed.

 


%Macro PCase (Dat=, Var=, LowList=);

 

Data Cased;
set &Dat;

%let VarCnt=%sysfunc(countw(&LowList));
%do i = 1 %to &VarCnt;
%let Var_Ind = %scan(&LowList,&i," ");
X1 = tranwrd(X1,"&Var_Ind", lowcase("&Var_Ind"));
%end;
run;
%mend PCase;

 

 

%let Low = %str(Or For And And/Or );

%PCase (Dat=A, Var=Original, LowList=&Low);

 

1 ACCEPTED SOLUTION

Accepted Solutions
Patrick
Opal | Level 21

It's normally best to make everything fully working without macro code. Here how this could look like:

data Original;
  input X1 $60.;
  cards;
SURGERY FOR BLEEDING
DELAYED AND/OR MISSED EXAMINATIONS
REMOVAL OF STITCHES
;

data makeItWork;
  set original;
  x2=propcase(x1);
  if 0 then x3=x2;
  x3=prxchange('s/\b(and|or|for|of)\b/\l\1/oi',-1,trim(x2));
run;

Now that it's working make it dynamic using a macro.

options mprint;
%macro pcase (ds=, outds=, var=, outvar=, lowlist=);
  %if &outds= %then %let outds=&ds;
  %if &outvar= %then %let outvar=&var;
  data &outds;
    set &ds;
    if 0 then &outvar=&var;
    &outvar=propcase(&var);
    &outvar=prxchange("s/\b(&lowlist)\b/\l\1/oi",-1,trim(&outvar));
  run;
%mend pcase;

%let low = %str(and|or|for|of );
%pcase (ds=Original, var=x1, lowlist=&low);

proc print data=Original;
run;

Below line is just to assign the new variable with the same length than an already existing variable (function prxchange() would create the new variable with a default length of 200).

if 0 then x3=x2;

 

Capture.JPG

 

And once you've got a working macro you can make it even more dynamic like allowing for changing multiple variables at once. And like always: You kind of need to keep the balance as the more you add the more complicated the code becomes. Below macro would already need quite a bit of inline comment so that you (or someone else) still can understand it it the future.

 

data Original;
  input X1 $60.;
  x2=x1;
  cards;
SURGERY FOR BLEEDING
DELAYED AND/OR MISSED EXAMINATIONS
REMOVAL OF STITCHES
;

%macro pcase (ds=, outds=, var=, outvar=, lowlist=);
  %if &outds= %then %let outds=&ds;
  %if &outvar= %then %let outvar=&var;
  data &outds;
    set &ds;
    %do i=1 %to %sysfunc(countw(&outvar));
      if 0 then %scan(&outvar,&i)=%scan(&var,&i);
      %scan(&outvar,&i)=propcase(%scan(&var,&i));
      %scan(&outvar,&i)=prxchange("s/\b(&lowlist)\b/\l\1/oi",-1,trim(%scan(&outvar,&i)));
    %end;
  run;
%mend pcase;

%let low = %str(and|or|for|of );
%pcase (ds=Original, var=x1 x2, outvar=newX1 newX2, lowlist=&low);

proc print data=Original;
run;

 

 

 

View solution in original post

8 REPLIES 8
PaigeMiller
Diamond | Level 26

We don't have data set A so we can't run your code.

 

It's also unclear why you need to use a macro loop here rather than a data step loop (and in my mind unnecessary to use macros at all).

--
Paige Miller
CHELS
Obsidian | Level 7

Thank you for your response. The reason why I am using a macro is because there will be more data steps added inside the macro to modify the case of the variable. For example, keeping acronyms in capital letter etc.  Here is an example of my Original data with the variable named X1

 

Data Original:

input X1 $60;

cards;

SURGERY FOR BLEEDING

DELAYED AND/OR MISSED EXAMINATIONS

REMOVAL OF STITCHES

;

run;

 

%Macro PCase (Dat=, Var=, LowList=);

Data Cased;
set &Dat;
X2 = propcase (&Var);

%let VarCnt=%sysfunc(countw(&LowList));
%do i = 1 %to &VarCnt;
%let Var_Ind = %scan(&LowList,&i," ");
X3 = tranwrd(X2, "&Var_Ind", lowcase("&Var_Ind"));
%end;
run;
%mend PCase;

 

It works If I define the list as: %let Low = %str(Or),

                                             %PCase (Dat=Original, Var=X1, LowList=&Low);

it which change all the 'Or' to 'or'.

 

If I define the list as  %let Low = %str(Or For And/Or) then nothing works.

PaigeMiller
Diamond | Level 26

I still don't see the need for a macro, when all computations occur within a data step.

 

But since you provide an example ... you have upper case data, and you are searching for mixed case, and no matches are found.

 

--
Paige Miller
CHELS
Obsidian | Level 7

Thank you!

Patrick
Opal | Level 21

It's normally best to make everything fully working without macro code. Here how this could look like:

data Original;
  input X1 $60.;
  cards;
SURGERY FOR BLEEDING
DELAYED AND/OR MISSED EXAMINATIONS
REMOVAL OF STITCHES
;

data makeItWork;
  set original;
  x2=propcase(x1);
  if 0 then x3=x2;
  x3=prxchange('s/\b(and|or|for|of)\b/\l\1/oi',-1,trim(x2));
run;

Now that it's working make it dynamic using a macro.

options mprint;
%macro pcase (ds=, outds=, var=, outvar=, lowlist=);
  %if &outds= %then %let outds=&ds;
  %if &outvar= %then %let outvar=&var;
  data &outds;
    set &ds;
    if 0 then &outvar=&var;
    &outvar=propcase(&var);
    &outvar=prxchange("s/\b(&lowlist)\b/\l\1/oi",-1,trim(&outvar));
  run;
%mend pcase;

%let low = %str(and|or|for|of );
%pcase (ds=Original, var=x1, lowlist=&low);

proc print data=Original;
run;

Below line is just to assign the new variable with the same length than an already existing variable (function prxchange() would create the new variable with a default length of 200).

if 0 then x3=x2;

 

Capture.JPG

 

And once you've got a working macro you can make it even more dynamic like allowing for changing multiple variables at once. And like always: You kind of need to keep the balance as the more you add the more complicated the code becomes. Below macro would already need quite a bit of inline comment so that you (or someone else) still can understand it it the future.

 

data Original;
  input X1 $60.;
  x2=x1;
  cards;
SURGERY FOR BLEEDING
DELAYED AND/OR MISSED EXAMINATIONS
REMOVAL OF STITCHES
;

%macro pcase (ds=, outds=, var=, outvar=, lowlist=);
  %if &outds= %then %let outds=&ds;
  %if &outvar= %then %let outvar=&var;
  data &outds;
    set &ds;
    %do i=1 %to %sysfunc(countw(&outvar));
      if 0 then %scan(&outvar,&i)=%scan(&var,&i);
      %scan(&outvar,&i)=propcase(%scan(&var,&i));
      %scan(&outvar,&i)=prxchange("s/\b(&lowlist)\b/\l\1/oi",-1,trim(%scan(&outvar,&i)));
    %end;
  run;
%mend pcase;

%let low = %str(and|or|for|of );
%pcase (ds=Original, var=x1 x2, outvar=newX1 newX2, lowlist=&low);

proc print data=Original;
run;

 

 

 

CHELS
Obsidian | Level 7

Thank you so much! I really appreciate you taking the time to code and teach me!

Quentin
Super User

Agree with @PaigeMiller this is not really a macro problem.  But that said, your current code works when I run it on sample data.

 

I would check the case of your real data, as tranwrd is case-sensitive when searching for words to replace.

 

Here's your code, with just one value of data hard-coded.

 

%Macro PCase (Dat=, Var=, LowList=);

Data Cased;
x1="Long sentence with Or For And And/Or" ;

%let VarCnt=%sysfunc(countw(&LowList));
%do i = 1 %to &VarCnt;
%let Var_Ind = %scan(&LowList,&i," ");
X1 = tranwrd(X1,"&Var_Ind", lowcase("&Var_Ind"));
%end;

put x1= ;
run;
%mend PCase;

%let Low = %str(Or For And And/Or );
%PCase (Dat=A, Var=Original, LowList=&Low)

Returns the desired:

x1=Long sentence with or for and and/or
NOTE: The data set WORK.CASED has 1 observations and 1 variables.
BASUG is hosting free webinars Next up: Don Henderson presenting on using hash functions (not hash tables!) to segment data on June 12. Register now at the Boston Area SAS Users Group event page: https://www.basug.org/events.
CHELS
Obsidian | Level 7
Thank you!

sas-innovate-2024.png

Available on demand!

Missed SAS Innovate Las Vegas? Watch all the action for free! View the keynotes, general sessions and 22 breakouts on demand.

 

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.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 8 replies
  • 828 views
  • 2 likes
  • 4 in conversation