Macros for SAS Application Developers
https://github.com/sasjs/core
Loading...
Searching...
No Matches
mp_chop.sas
Go to the documentation of this file.
1/**
2 @file
3 @brief Splits a file of ANY SIZE by reference to a search string.
4 @details Provide a fileref and a search string to chop off part of a file.
5
6 Works by reading in the file byte by byte, then marking the beginning and end
7 of each matched string, before finally doing the chop.
8
9 Choose whether to keep the FIRST or the LAST section of the file. Optionally,
10 use an OFFSET to fix the precise chop point.
11
12 Usage:
13
14 %let src="%sysfunc(pathname(work))/file.txt";
15 %let str=Chop here!;
16 %let out1="%sysfunc(pathname(work))/file1.txt";
17 %let out2="%sysfunc(pathname(work))/file2.txt";
18 %let out3="%sysfunc(pathname(work))/file3.txt";
19 %let out4="%sysfunc(pathname(work))/file4.txt";
20
21 data _null_;
22 file &src;
23 put "startsection&str.endsection";
24 run;
25
26 %mp_chop(&src, matchvar=str, keep=FIRST, outfile=&out1)
27 %mp_chop(&src, matchvar=str, keep=LAST, outfile=&out2)
28 %mp_chop(&src, matchvar=str, keep=FIRST, matchpoint=END, outfile=&out3)
29 %mp_chop(&src, matchvar=str, keep=LAST, matchpoint=END, outfile=&out4)
30
31 filename results (&out1 &out2 &out3 &out4);
32 data _null_;
33 infile results;
34 input;
35 list;
36 run;
37
38 Results:
39 @li `startsection`
40 @li `Chop here!endsection`
41 @li `startsectionChop here!`
42 @li `endsection`
43
44 For more examples, see mp_chop.test.sas
45
46 @param [in] infile The QUOTED path to the file on which to perform the chop
47 @param [in] matchvar= () Macro variable NAME containing the string to split by
48 @param [in] matchpoint= (START) Valid values:
49 @li START - chop at the beginning of the string in `matchvar`.
50 @li END - chop at the end of the string in `matchvar`.
51 @param [in] offset= (0) An adjustment to the precise chop location, by
52 by reference to the `matchpoint`. Should be a positive or negative integer.
53 @param [in] keep= (FIRST) Valid values:
54 @li FIRST - keep the section of the file before the chop
55 @li LAST - keep the section of the file after the chop
56 @param [in] mdebug= (0) Set to 1 to provide macro debugging
57 @param [out] outfile= (0)
58 Optional QUOTED path to the adjusted output file (avoids
59 overwriting the first file).
60
61 <h4> SAS Macros </h4>
62 @li mf_getuniquefileref.sas
63 @li mf_getuniquename.sas
64
65 <h4> Related Macros </h4>
66 @li mp_abort.sas
67 @li mp_gsubfile.sas
68 @li mp_replace.sas
69 @li mp_chop.test.sas
70
71 @version 9.4
72 @author Allan Bowe
73
74**/
75
76%macro mp_chop(infile,
77 matchvar=,
78 matchpoint=START,
79 keep=FIRST,
80 offset=0,
81 mdebug=0,
82 outfile=0
83)/*/STORE SOURCE*/;
84
85%local fref0 dttm ds1 outref;
86%let fref0=%mf_getuniquefileref();
87%let ds1=%mf_getuniquename(prefix=allchars);
88%let ds2=%mf_getuniquename(prefix=startmark);
89
90%if &outfile=0 %then %let outfile=&infile;
91
92%mp_abort(iftrue= (%length(%superq(&matchvar))=0)
93 ,mac=mp_chop.sas
94 ,msg=%str(&matchvar is an empty variable)
95)
96
97/* START */
98%let dttm=%sysfunc(datetime());
99
100filename &fref0 &infile lrecl=1 recfm=n;
101
102/* create dataset with one char per row */
103data &ds1;
104 infile &fref0;
105 input sourcechar $char1. @@;
106 format sourcechar hex2.;
107run;
108
109/* get start & stop position of first matchvar string (one row, two vars) */
110data &ds2;
111 /* set find string to length in bytes to cover trailing spaces */
112 length string $ %length(%superq(&matchvar));
113 string =symget("&matchvar");
114 drop string;
115
116 firstchar=char(string,1);
117 findlen=lengthm(string); /* <- for trailing bytes */
118
119 do _N_=1 to nobs;
120 set &ds1 nobs=nobs point=_N_;
121 if sourcechar=firstchar then do;
122 pos=1;
123 s=0;
124 do point=_N_ to min(_N_ + findlen -1,nobs);
125 set &ds1 point=point;
126 if sourcechar=char(string, pos) then s + 1;
127 else goto _leave_;
128 pos+1;
129 end;
130 _leave_:
131 if s=findlen then do;
132 START =_N_;
133 _N_ =_N_+ s - 1;
134 STOP =_N_;
135 output;
136 /* matched! */
137 stop;
138 end;
139 end;
140 end;
141 stop;
142 keep START STOP;
143run;
144
145%local split;
146%let split=0;
147data _null_;
148 set &ds2;
149 if "&matchpoint"='START' then do;
150 if "&keep"='FIRST' then mp=start;
151 else if "&keep"='LAST' then mp=start-1;
152 end;
153 else if "&matchpoint"='END' then do;
154 if "&keep"='FIRST' then mp=stop+1;
155 else if "&keep"='LAST' then mp=stop;
156 end;
157 split=mp+&offset;
158 call symputx('split',split,'l');
159%if &mdebug=1 %then %do;
160 put (_all_)(=);
161 %put &=offset;
162%end;
163run;
164%if &split=0 %then %do;
165 %put &sysmacroname: No match found in &infile for string %superq(&matchvar);
166 %return;
167%end;
168
169data _null_;
170 file &outfile recfm=n;
171 set &ds1;
172%if &keep=FIRST %then %do;
173 if _n_ ge &split then stop;
174%end;
175%else %do;
176 if _n_ gt &split;
177%end;
178 put sourcechar char1.;
179run;
180
181%if &mdebug=0 %then %do;
182 filename &fref0 clear;
183%end;
184%else %do;
185 data _null_;
186 infile &outfile lrecl=32767;
187 input;
188 list;
189 if _n_>200 then stop;
190 run;
191%end;
192/* END */
193%put &sysmacroname took %sysevalf(%sysfunc(datetime())-&dttm) seconds to run;
194
195%mend mp_chop;