Macros for SAS Application Developers
https://github.com/sasjs/core
Loading...
Searching...
No Matches
mp_replace.sas
Go to the documentation of this file.
1/**
2 @file
3 @brief Performs a text substitution on a file
4 @details Performs a find and replace on a file, either in place or to a new
5 file. Can be used on files where lines are longer than 32767.
6
7 Works by reading in the file byte by byte, then marking the beginning and end
8 of each matched string, before finally doing the replace.
9
10 Full credit for this highly efficient and syntactically satisfying SAS logic
11 goes to [Bartosz Jabłoński](https://www.linkedin.com/in/yabwon), founder of
12 the [SAS Packages](https://github.com/yabwon/SAS_PACKAGES) framework.
13
14 Usage:
15
16 %let file="%sysfunc(pathname(work))/file.txt";
17 %let str=replace/me;
18 %let rep=with/this;
19 data _null_;
20 file &file;
21 put 'blahblah';
22 put "blahblah&str.blah";
23 put 'blahblahblah';
24 run;
25 %mp_replace(&file, findvar=str, replacevar=rep)
26 data _null_;
27 infile &file;
28 input;
29 list;
30 run;
31
32 Note - if you are running a version of SAS that will allow the io package in
33 LUA, you can also use this macro: mp_gsubfile.sas
34
35 @param [in] infile The QUOTED path to the file on which to perform the
36 substitution. Note that you can extract the pathname from a fileref using
37 the pathname function, eg: `"%sysfunc(pathname(fref))"`;
38 @param [in] findvar= Macro variable NAME containing the string to search for
39 @param [in] replacevar= Macro variable NAME containing the replacement string
40 @param [out] outfile= (0) Optional QUOTED path to the adjusted output file (to
41 avoid overwriting the first file).
42
43 <h4> SAS Macros </h4>
44 @li mf_getuniquefileref.sas
45 @li mf_getuniquename.sas
46
47 <h4> Related Macros </h4>
48 @li mp_chop.sas
49 @li mp_gsubfile.sas
50 @li mp_replace.test.sas
51
52 @version 9.4
53 @author Bartosz Jabłoński
54 @author Allan Bowe
55**/
56
57%macro mp_replace(infile,
58 findvar=,
59 replacevar=,
60 outfile=0
61)/*/STORE SOURCE*/;
62
63%local inref dttm ds1 replen;
64%let inref=%mf_getuniquefileref();
65%let outref=%mf_getuniquefileref();
66%if &outfile=0 %then %let outfile=&infile;
67%let ds1=%mf_getuniquename(prefix=allchars);
68%let ds2=%mf_getuniquename(prefix=startmark);
69/* a blank replacement is a deletion, so the length of the replacement is read
70 * once and the characters are simply dropped when it is empty */
71%let replen=%length(%superq(&replacevar));
72
73/* START */
74%let dttm=%sysfunc(datetime());
75
76filename &inref &infile lrecl=1 recfm=n;
77
78data &ds1;
79 infile &inref;
80 input sourcechar $char1. @@;
81 format sourcechar hex2.;
82run;
83
84data &ds2;
85 /* set find string to length in bytes to cover trailing spaces */
86 length string $ %length(%superq(&findvar));
87 string =symget("&findvar");
88 drop string;
89
90 firstchar=char(string,1);
91 findlen=lengthm(string); /* <- for trailing bytes */
92
93 do _N_=1 to nobs;
94 set &ds1 nobs=nobs point=_N_;
95 if sourcechar=firstchar then do;
96 pos=1;
97 s=0;
98 do point=_N_ to min(_N_ + findlen -1,nobs);
99 set &ds1 point=point;
100 if sourcechar=char(string, pos) then s + 1;
101 else goto _leave_;
102 pos+1;
103 end;
104 _leave_:
105 if s=findlen then do;
106 START =_N_;
107 _N_ =_N_+ s - 1;
108 STOP =_N_;
109 output;
110 end;
111 end;
112 end;
113 stop;
114 keep START STOP;
115run;
116
117data &ds1;
118 declare hash HS(dataset:"&ds2(keep=start)");
119 HS.defineKey("start");
120 HS.defineDone();
121 declare hash HE(dataset:"&ds2(keep=stop)");
122 HE.defineKey("stop");
123 HE.defineDone();
124 do until(eof);
125 set &ds1 end=eof curobs =n;
126 start = ^HS.check(key:n);
127 stop = ^HE.check(key:n);
128 length strt $ 1;
129 strt =put(start,best. -L);
130 retain out 1;
131 if out then output;
132 if start then out=0;
133 if stop then out=1;
134 end;
135 stop;
136 keep sourcechar strt;
137run;
138
139filename &outref &outfile recfm=n;
140
141data _null_;
142 %if &replen>0 %then %do;
143 length replace $ &replen;
144 replace=symget("&replacevar");
145 %end;
146 file &outref;
147 do until(eof);
148 set &ds1 end=eof;
149 if strt ="1" then do;
150 %if &replen>0 %then %do;
151 put replace char.;
152 %end;
153 end;
154 else put sourcechar char1.;
155 end;
156 stop;
157run;
158
159/* END */
160/* %put &sysmacroname took %sysevalf(%sysfunc(datetime())-&dttm) secs to run; */
161
162%mend mp_replace;