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
37 @param [in] findvar= Macro variable NAME containing the string to search for
38 @param [in] replacevar= Macro variable NAME containing the replacement string
39 @param [out] outfile= (0) Optional QUOTED path to the adjusted output file (to
40 avoid overwriting the first file).
41
42 <h4> SAS Macros </h4>
43 @li mf_getuniquefileref.sas
44 @li mf_getuniquename.sas
45
46 <h4> Related Macros </h4>
47 @li mp_chop.sas
48 @li mp_gsubfile.sas
49 @li mp_replace.test.sas
50
51 @version 9.4
52 @author Bartosz Jabłoński
53 @author Allan Bowe
54**/
55
56%macro mp_replace(infile,
57 findvar=,
58 replacevar=,
59 outfile=0
60)/*/STORE SOURCE*/;
61
62%local inref dttm ds1;
63%let inref=%mf_getuniquefileref();
64%let outref=%mf_getuniquefileref();
65%if &outfile=0 %then %let outfile=&infile;
66%let ds1=%mf_getuniquename(prefix=allchars);
67%let ds2=%mf_getuniquename(prefix=startmark);
68
69/* START */
70%let dttm=%sysfunc(datetime());
71
72filename &inref &infile lrecl=1 recfm=n;
73
74data &ds1;
75 infile &inref;
76 input sourcechar $char1. @@;
77 format sourcechar hex2.;
78run;
79
80data &ds2;
81 /* set find string to length in bytes to cover trailing spaces */
82 length string $ %length(%superq(&findvar));
83 string =symget("&findvar");
84 drop string;
85
86 firstchar=char(string,1);
87 findlen=lengthm(string); /* <- for trailing bytes */
88
89 do _N_=1 to nobs;
90 set &ds1 nobs=nobs point=_N_;
91 if sourcechar=firstchar then do;
92 pos=1;
93 s=0;
94 do point=_N_ to min(_N_ + findlen -1,nobs);
95 set &ds1 point=point;
96 if sourcechar=char(string, pos) then s + 1;
97 else goto _leave_;
98 pos+1;
99 end;
100 _leave_:
101 if s=findlen then do;
102 START =_N_;
103 _N_ =_N_+ s - 1;
104 STOP =_N_;
105 output;
106 end;
107 end;
108 end;
109 stop;
110 keep START STOP;
111run;
112
113data &ds1;
114 declare hash HS(dataset:"&ds2(keep=start)");
115 HS.defineKey("start");
116 HS.defineDone();
117 declare hash HE(dataset:"&ds2(keep=stop)");
118 HE.defineKey("stop");
119 HE.defineDone();
120 do until(eof);
121 set &ds1 end=eof curobs =n;
122 start = ^HS.check(key:n);
123 stop = ^HE.check(key:n);
124 length strt $ 1;
125 strt =put(start,best. -L);
126 retain out 1;
127 if out then output;
128 if start then out=0;
129 if stop then out=1;
130 end;
131 stop;
132 keep sourcechar strt;
133run;
134
135filename &outref &outfile recfm=n;
136
137data _null_;
138 length replace $ %length(%superq(&replacevar));
139 replace=symget("&replacevar");
140 file &outref;
141 do until(eof);
142 set &ds1 end=eof;
143 if strt ="1" then put replace char.;
144 else put sourcechar char1.;
145 end;
146 stop;
147run;
148
149/* END */
150%put &sysmacroname took %sysevalf(%sysfunc(datetime())-&dttm) seconds to run;
151
152%mend mp_replace;