mirror of
https://github.com/sasjs/core.git
synced 2025-12-10 22:14:35 +00:00
153 lines
3.7 KiB
SAS
153 lines
3.7 KiB
SAS
/**
|
|
@file
|
|
@brief Performs a text substitution on a file
|
|
@details Performs a find and replace on a file, either in place or to a new
|
|
file. Can be used on files where lines are longer than 32767.
|
|
|
|
Works by reading in the file byte by byte, then marking the beginning and end
|
|
of each matched string, before finally doing the replace.
|
|
|
|
Full credit for this highly efficient and syntactically satisfying SAS logic
|
|
goes to [Bartosz Jabłoński](https://www.linkedin.com/in/yabwon), founder of
|
|
the [SAS Packages](https://github.com/yabwon/SAS_PACKAGES) framework.
|
|
|
|
Usage:
|
|
|
|
%let file="%sysfunc(pathname(work))/file.txt";
|
|
%let str=replace/me;
|
|
%let rep=with/this;
|
|
data _null_;
|
|
file &file;
|
|
put 'blahblah';
|
|
put "blahblah&str.blah";
|
|
put 'blahblahblah';
|
|
run;
|
|
%mp_replace(&file, findvar=str, replacevar=rep)
|
|
data _null_;
|
|
infile &file;
|
|
input;
|
|
list;
|
|
run;
|
|
|
|
Note - if you are running a version of SAS that will allow the io package in
|
|
LUA, you can also use this macro: mp_gsubfile.sas
|
|
|
|
@param [in] infile The QUOTED path to the file on which to perform the
|
|
substitution
|
|
@param [in] findvar= Macro variable NAME containing the string to search for
|
|
@param [in] replacevar= Macro variable NAME containing the replacement string
|
|
@param [out] outfile= (0) Optional QUOTED path to the adjusted output file (to
|
|
avoid overwriting the first file).
|
|
|
|
<h4> SAS Macros </h4>
|
|
@li mf_getuniquefileref.sas
|
|
@li mf_getuniquename.sas
|
|
|
|
<h4> Related Macros </h4>
|
|
@li mp_chop.sas
|
|
@li mp_gsubfile.sas
|
|
@li mp_replace.test.sas
|
|
|
|
@version 9.4
|
|
@author Bartosz Jabłoński
|
|
@author Allan Bowe
|
|
**/
|
|
|
|
%macro mp_replace(infile,
|
|
findvar=,
|
|
replacevar=,
|
|
outfile=0
|
|
)/*/STORE SOURCE*/;
|
|
|
|
%local inref dttm ds1;
|
|
%let inref=%mf_getuniquefileref();
|
|
%let outref=%mf_getuniquefileref();
|
|
%if &outfile=0 %then %let outfile=&infile;
|
|
%let ds1=%mf_getuniquename(prefix=allchars);
|
|
%let ds2=%mf_getuniquename(prefix=startmark);
|
|
|
|
/* START */
|
|
%let dttm=%sysfunc(datetime());
|
|
|
|
filename &inref &infile lrecl=1 recfm=n;
|
|
|
|
data &ds1;
|
|
infile &inref;
|
|
input sourcechar $char1. @@;
|
|
format sourcechar hex2.;
|
|
run;
|
|
|
|
data &ds2;
|
|
/* set find string to length in bytes to cover trailing spaces */
|
|
length string $ %length(%superq(&findvar));
|
|
string =symget("&findvar");
|
|
drop string;
|
|
|
|
firstchar=char(string,1);
|
|
findlen=lengthm(string); /* <- for trailing bytes */
|
|
|
|
do _N_=1 to nobs;
|
|
set &ds1 nobs=nobs point=_N_;
|
|
if sourcechar=firstchar then do;
|
|
pos=1;
|
|
s=0;
|
|
do point=_N_ to min(_N_ + findlen -1,nobs);
|
|
set &ds1 point=point;
|
|
if sourcechar=char(string, pos) then s + 1;
|
|
else goto _leave_;
|
|
pos+1;
|
|
end;
|
|
_leave_:
|
|
if s=findlen then do;
|
|
START =_N_;
|
|
_N_ =_N_+ s - 1;
|
|
STOP =_N_;
|
|
output;
|
|
end;
|
|
end;
|
|
end;
|
|
stop;
|
|
keep START STOP;
|
|
run;
|
|
|
|
data &ds1;
|
|
declare hash HS(dataset:"&ds2(keep=start)");
|
|
HS.defineKey("start");
|
|
HS.defineDone();
|
|
declare hash HE(dataset:"&ds2(keep=stop)");
|
|
HE.defineKey("stop");
|
|
HE.defineDone();
|
|
do until(eof);
|
|
set &ds1 end=eof curobs =n;
|
|
start = ^HS.check(key:n);
|
|
stop = ^HE.check(key:n);
|
|
length strt $ 1;
|
|
strt =put(start,best. -L);
|
|
retain out 1;
|
|
if out then output;
|
|
if start then out=0;
|
|
if stop then out=1;
|
|
end;
|
|
stop;
|
|
keep sourcechar strt;
|
|
run;
|
|
|
|
filename &outref &outfile recfm=n;
|
|
|
|
data _null_;
|
|
length replace $ %length(%superq(&replacevar));
|
|
replace=symget("&replacevar");
|
|
file &outref;
|
|
do until(eof);
|
|
set &ds1 end=eof;
|
|
if strt ="1" then put replace char.;
|
|
else put sourcechar char1.;
|
|
end;
|
|
stop;
|
|
run;
|
|
|
|
/* END */
|
|
%put &sysmacroname took %sysevalf(%sysfunc(datetime())-&dttm) seconds to run;
|
|
|
|
%mend mp_replace;
|