%macro CtoN(version, data=, var=_character_, out=, prefix=, suffix=_N, order=internal, options=replace format) / minoperator; %let time = %sysfunc(datetime()); %let _version=1.0; %if &version ne %then %put &sysmacroname macro Version &_version; %let _opts = %sysfunc(getoption(notes)); %if &version ne debug %then %str(options nonotes;); /* Check for newer version */ %if %sysevalf(&sysver >= 8.2) %then %do; %let _notfound=0; filename _ver url 'http://ftp.sas.com/techsup/download/stat/versions.dat' termstr=crlf; data _null_; infile _ver end=_eof; input name:$15. ver; if upcase(name)="&sysmacroname" then do; call symput("_newver",ver); stop; end; if _eof then call symput("_notfound",1); run; %if &syserr ne 0 or &_notfound=1 %then %put &sysmacroname: Unable to check for newer version; %else %if %sysevalf(&_newver > &_version) %then %do; %put &sysmacroname: A newer version of the &sysmacroname macro is available.; %put %str( ) You can get the newer version at this location:; %put %str( ) http://support.sas.com/; %end; %end; /* Check inputs */ %if &data= or %sysfunc(exist(&data)) ne 1 %then %do; %put ERROR: DATA= data set not specified or not found.; %goto exit; %end; %if &var= %then %do; %put ERROR: VAR= is required.; %goto exit; %end; %if &prefix= and &suffix= %then %do; %put ERROR: At least one of PREFIX= or SUFFIX= must not be null.; %goto exit; %end; %let valorder=INTERNAL DATA FORMATTED FREQ; %if not (%upcase(&order) in &valorder) %then %do; %put ERROR: Valid values of ORDER= are INTERNAL, DATA, FORMATTED, FREQ.; %goto exit; %end; %let validopts=REPLACE NOREPLACE FORMAT NOFORMAT; %let replace=1; %let format=1; %let i=1; %do %while (%scan(&options,&i) ne %str() ); %let option&i=%upcase(%scan(&options,&i)); %if &&option&i=NOREPLACE %then %let replace=0; %if &&option&i=NOFORMAT %then %let format=0; %let chk=%eval(&&option&i in &validopts); %if not &chk %then %do; %put ERROR: Valid values of OPTIONS= are REPLACE, NOREPLACE, FORMAT, NOFORMAT.; %goto exit; %end; %let i=%eval(&i+1); %end; %if &out= %then %do; %let overvalid=%eval(%length(&data)-30); %if &overvalid>0 %then %do; %let out=%substr(&data,1,%eval(%length(&data)-&overvalid))_N; %end; %else %let out=&data._N; %end; /* Initialize and prepare list of variables to process */ data _newvars; run; %let addlen=%eval(%length(&prefix)+%length(&suffix)); %if %upcase(&var)=_CHARACTER_ %then %do; data _null_; set &data; array c (*) _character_; length _varlist $32767 _cvar $200; do _i=1 to dim(c); call vname(c(_i),_cvar); _varlist=catx(' ',_varlist,_cvar); end; call symputx("varlist",_varlist); stop; run; %end; %else %let varlist=&var; %let i=1; %do %while (%scan(&varlist,&i) ne %str() ); %let i=%eval(&i+1); %end; %let nvar=%eval(&i-1); %let onvar=%sysfunc(floor(%sysfunc(log10(&nvar)))); /* Process each variable */ %let j=1; %do %while (%scan(&varlist,&j) ne %str() ); %let var=%scan(&varlist,&j); %let dsid=%sysfunc(open(&data)); %if &dsid %then %do; %let varnum=%sysfunc(varnum(&dsid,&var)); %if &varnum=0 %then %do; %put ERROR: VAR= variable, %upcase(&var), not found.; %let rc=%sysfunc(close(&dsid)); %goto exit; %end; %if %sysfunc(vartype(&dsid,&varnum))=N %then %do; %put ERROR: The VAR= variable is already numeric.; %let rc=%sysfunc(close(&dsid)); %goto exit; %end; %let rc=%sysfunc(close(&dsid)); %end; %else %do; %put ERROR: Data set, %upcase(&data), could not be opened.; %goto exit; %end; proc freq data=&data order=ℴ table &var / noprint out=_tmp(where=(not missing(&var))); run; data _null_; set _tmp nobs=nlev end=eof; call symput(cats('l',_n_),catt(&var)); if eof then call symputx('nlev',nlev); run; %if &format %then %do; %let lastdig=%sysfunc(anydigit(&var,-32)); %if &lastdig=%length(&var) %then %do; %if %length(&var)+3+&onvar > 32 %then %let trunc=%eval(3+&onvar); %else %let trunc=0; %let fmtname=%substr(&var,1,&lastdig-&trunc)_&j._; %end; %else %let fmtname=&var; proc format; value &fmtname %do i=1 %to &nlev; &i="%superq(l&i)" %end; ; run; %end; %let overvalid=%eval(%length(&var)+&addlen-32); %if &overvalid>0 %then %do; %let newname=&prefix%substr(&var,1,%eval(%length(&var)-&overvalid))&suffix; %end; %else %let newname=&prefix&var&suffix; data _newvar; set &data; select (&var); %do i=1 %to &nlev; when ("%superq(l&i)") &newname = &i; %end; otherwise &newname = .; end; %if &format %then %do; format &newname &fmtname..; %end; %else %do; format &newname; %end; keep &newname; run; %if &replace %then %do; data _newvar; set _newvar; &var=&newname; %if &format %then %do; format &var &fmtname..; %end; %else %do; format &var; %end; keep &var; run; %end; data _newvars; merge _newvars _newvar; run; %let j=%eval(&j+1); %end; /* Create final data set and clean up */ options notes; data &out; merge &data %if &replace %then (drop=&varlist); _newvars; run; options nonotes; %if %upcase(&version) ne DEBUG %then %do; proc datasets nolist; delete _tmp _newvar _newvars; run; quit; %end; %exit: options &_opts; %let time = %sysfunc(round(%sysevalf(%sysfunc(datetime()) - &time), 0.01)); %put NOTE: The &sysmacroname macro used &time seconds.; %mend;