Macros for SAS Application Developers
https://github.com/sasjs/core
Loading...
Searching...
No Matches
mp_validatecol.sas
Go to the documentation of this file.
1/**
2 @file
3 @brief Used to validate values in a data step
4 @details Useful when sanitising inputs, to ensure that they arrive with a
5 certain pattern.
6 Usage:
7
8 data test;
9 infile datalines4 dsd;
10 input;
11 libds=_infile_;
12 %mp_validatecol(libds,LIBDS,is_libds)
13 datalines4;
14 some.libname
15 !lib.blah
16 %abort
17 definite.ok
18 not.ok!
19 nineletrs._
20 ;;;;
21 run;
22
23 For more examples, see mp_validatecol.test.sas
24
25 Tip - when contributing, use https://regex101.com to test the regex validity!
26
27 @param [in] incol The column to be validated
28 @param [in] rule The rule to apply. Current rules:
29 @li ISINT - checks if the variable is an integer
30 @li ISLIB - checks if the value is a valid libref (NOT whether it exists)
31 @li ISNAME - checks if the value is a valid SAS NAME (V7 rules - up to 32
32 chars, starting with a letter or underscore, followed by letters,
33 numbers or underscores)
34 @li ISNUM - checks if the variable is numeric
35 @li LIBDS - matches LIBREF.DATASET format
36 @li FORMAT - checks if the provided format is syntactically valid
37 @li ISPATH - checks that the value is an absolute path this platform would
38 accept. Shape only - whether the path exists is a different question
39 (mf_isdir / fileexist)
40 @param [out] outcol The variable to create, with the results of the match
41
42 <h4> SAS Macros </h4>
43 @li mf_getuniquename.sas
44
45 <h4> Related Macros </h4>
46 @li mp_validatecol.test.sas
47
48 @version 9.3
49**/
50
51%macro mp_validatecol(incol,rule,outcol);
52
53/* tempcol is given a unique name with every invocation */
54%local tempcol;
55%let tempcol=%mf_getuniquename();
56
57%if &rule=ISINT %then %do;
58 &outcol=0;
59 if not missing(&incol) then do;
60 &tempcol=input(&incol,?? best32.);
61 if not missing(&tempcol) then if mod(&tempcol,1)=0 then &outcol=1;
62 end;
63 drop &tempcol;
64%end;
65%else %if &rule=ISNUM %then %do;
66 /*
67 credit SOREN LASSEN
68 https://sasmacro.blogspot.com/2009/06/welcome-isnum-macro.html
69 */
70 &tempcol=input(&incol,?? best32.);
71 if missing(&tempcol) then &outcol=0;
72 else &outcol=1;
73 drop &tempcol;
74%end;
75%else %if &rule=ISLIB %then %do;
76 if _n_=1 then do;
77 retain &tempcol;
78 &tempcol=prxparse('/^[_a-z]\w{0,7}$/i');
79 if missing(&tempcol) then do;
80 putlog 'ERR' +(-1) "OR: Invalid expression for ISLIB";
81 stop;
82 end;
83 drop &tempcol;
84 end;
85 if prxmatch(&tempcol, trim(&incol)) then &outcol=1;
86 else &outcol=0;
87%end;
88%else %if &rule=ISNAME %then %do;
89 /* match a valid SAS name (V7 rules) */
90 if _n_=1 then do;
91 retain &tempcol;
92 &tempcol=prxparse('/^[_a-z]\w{0,31}$/i');
93 if missing(&tempcol) then do;
94 putlog 'ERR' +(-1) "OR: Invalid expression for ISNAME";
95 stop;
96 end;
97 drop &tempcol;
98 end;
99 if prxmatch(&tempcol, trim(&incol)) then &outcol=1;
100 else &outcol=0;
101%end;
102%else %if &rule=LIBDS %then %do;
103 /* match libref.dataset */
104 if _n_=1 then do;
105 retain &tempcol;
106 &tempcol=prxparse('/^[_a-z]\w{0,7}\.[_a-z]\w{0,31}$/i');
107 if missing(&tempcol) then do;
108 putlog 'ERR' +(-1) "OR: Invalid expression for LIBDS";
109 stop;
110 end;
111 drop &tempcol;
112 end;
113 if prxmatch(&tempcol, trim(&incol)) then &outcol=1;
114 else &outcol=0;
115%end;
116%else %if &rule=ISPATH %then %do;
117 /*
118 An absolute path on the current platform. This is a shape check: a path
119 that passes may still not exist, and one that fails would be rejected by
120 the operating system rather than read as a folder.
121 */
122 &outcol=0;
123 if length(trim(&incol))>0 and anycntrl(&incol)=0 then do;
124 %if "%upcase(&sysscp)"="WIN" or "%upcase(&sysscp)"="DNTHOST" %then %do;
125 /* a drive root (C:/folder) */
126 if substr(&incol,2,1)=':' and substr(&incol,3,1) in ('\','/') then
127 &outcol=1;
128 /* a UNC share needs both a host and a share - \\host\ is not openable */
129 if substr(&incol,1,2)='\\' and scan(&incol,2,'\') ne '' then
130 &outcol=1;
131 /* characters windows does not accept in a name, and a colon
132 anywhere but the drive separator */
133 if &outcol=1 then do;
134 if index(substr(&incol,3),':')>0 then &outcol=0;
135 if index(&incol,byte(34))>0 then &outcol=0;
136 if index(&incol,'<')>0 then &outcol=0;
137 if index(&incol,'>')>0 then &outcol=0;
138 if index(&incol,'|')>0 then &outcol=0;
139 if index(&incol,'?')>0 then &outcol=0;
140 if index(&incol,'*')>0 then &outcol=0;
141 end;
142 %end;
143 %else %do;
144 if substr(&incol,1,1)='/' then &outcol=1;
145 %end;
146 end;
147%end;
148%else %if &rule=FORMAT %then %do;
149 /* match valid SAS format*/
150 if _n_=1 then do;
151 retain &tempcol;
152 &tempcol=prxparse('/^(?:[_a-z\$]\w{0,31}|[0-9]+)\.[0-9]*$/i');
153 if missing(&tempcol) then do;
154 putlog 'ERR' +(-1) "OR: Invalid expression for FORMAT";
155 stop;
156 end;
157 drop &tempcol;
158 end;
159 if prxmatch(&tempcol, trim(&incol)) then &outcol=1;
160 else &outcol=0;
161%end;
162
163%mend mp_validatecol;