forked from Jiangtang/SAS_ListProcessing
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path_ListProcessing
2785 lines (2443 loc) · 97.9 KB
/
_ListProcessing
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*%add_string
Purpose: Add a text string to each variable in a list as either a prefix or suffix.
dependence: %num_tokens
Required arguments:
words – the variable list
str – the text string to add to each variable in the &words list
Optional arguments:
location – whether to add the text string as a prefix or suffix [prefix|suffix, default: suffix]
delim – the character(s) separating each variable in the &words list [default: space]
Examples:
%put %add_string(a b c, _max); *produces the text a_max b_max c_max;
%put %add_string(a b c, max_, location=prefix); *produces the text max_a max_b max_c;
%put %add_string(%str(a,b,c), _max, delim=%str(,)); *produces the text a_max,b_max,c_max;
Credit:
source code from Robert J. Morris, Text Utility Macros for Manipulating Lists of Variable Names
(SUGI 30, 2005) www2.sas.com/proceedings/sugi30/029-30.pdf
*/
%macro add_string(words, str, delim=%str( ), location=suffix);
%local outstr i word num_words;
%* Verify macro arguments. ;
%if (%length(&words) eq 0) %then %do;
%put ***ERROR(add_string): Required argument 'words' is missing.;
%goto exit;
%end;
%if (%length(&str) eq 0) %then %do;
%put ***ERROR(add_string): Required argument 'str' is missing.;
%goto exit;
%end;
%if (%upcase(&location) ne SUFFIX and %upcase(&location) ne PREFIX) %then %do;
%put ***ERROR(add_string): Optional argument 'location' must be;
%put *** set to SUFFIX or PREFIX.;
%goto exit;
%end;
%* Build the outstr by looping through the words list and adding the
* requested string onto each word. ;
%let outstr = ;
%let num_words = %num_tokens(&words, delim=&delim);
%do i=1 %to &num_words;
%let word = %scan(&words, &i, &delim);
%if (&i eq 1) %then %do;
%if (%upcase(&location) eq PREFIX) %then %do;
%let outstr = &str&word;
%end;
%else %do;
%let outstr = &word&str;
%end;
%end;
%else %do;
%if (%upcase(&location) eq PREFIX) %then %do;
%let outstr = &outstr&delim&str&word;
%end;
%else %do;
%let outstr = &outstr&delim&word&str;
%end;
%end;
%end;
%* Output the new list of words. ;
&outstr
%exit:
%mend add_string;
/*<pre><b>
/ Program : appmvar.sas
/ Version : 1.0
/ Author : Roland Rashleigh-Berry (http://www.datasavantconsulting.com/roland/)
/ Date : 23-Aug-2012
/ Purpose : Function-style macro to append a string onto an existing macro
/ variable.
/ SubMacros : none
/ Notes : This macro has very limited functionality and was written to make
/ your code less messy. It is where you are accumulating messages in
/ a macro variable and when you append onto the end of it you want
/ there to be a separating string to delimit the different messages
/ such as using %str(; ). This macro takes care of the logic of
/ checking what is already there and what you want to add and will
/ only use the separating string if the macro variable being
/ appended onto has contents as well as the string you are appending
/ is non-empty.
/ Usage : %let err_msg=%appmvar(err_msg,This is another error message);
/ %let err_msg=%appmvar(err_msg,
/ Add this comma-delimited list (%nrbquote(&list)));
/===============================================================================
/ PARAMETERS:
/-------name------- -------------------------description------------------------
/ mvar (pos) Name of macro variable to append onto
/ append (pos) String to append
/ sep=%str(; ) Separating string (defaults to "; ")
/===============================================================================
/ AMENDMENT HISTORY:
/ init --date-- mod-id ----------------------description------------------------
/ rrb 23Aug12 new (v1.0)
/===============================================================================
/ This is public domain software. No guarantee as to suitability or accuracy is
/ given or implied. User uses this code entirely at their own risk.
/=============================================================================*/
%macro appmvar(mvar,append,sep=%str(; ));
%if %length(&&&mvar) and %length(&append) %then %do;
&&&mvar&sep&append
%end;
%else %if %length(&append) %then %do;
&append
%end;
%else %do;
&&&mvar
%end;
%mend appmvar;
/*<pre><b>
/ Program : capmac.sas
/ Version : 1.0
/ Author : Roland Rashleigh-Berry (http://www.datasavantconsulting.com/roland/)
/ Date : 11-Jan-2013
/ Purpose : Function-style macro to capitalise the first letter of each
/ word in a macro string.
/ SubMacros : %words %quotelst (%qlowcase from SI supplied autocall library
/ is called so this must be on the sasautos path).
/ Notes : You can specify words to ignore. Case must match for these.
/ If the string you supply might contain commas or unbalanced
/ quotes then you should use %nrbquote() around it. See usage.
/ Usage : %let tidy=%capmac(%nrbquote(A, B AND C'S RESULTS));
/ %put %capmac(%bquote(A, B AND C'S RESULTS));
/
/===============================================================================
/ PARAMETERS:
/-------name------- -------------------------description------------------------
/ string (pos) Macro string to convert
/ ignore List of strings (separated by spaces) to ignore
/===============================================================================
/ AMENDMENT HISTORY:
/ init --date-- mod-id ----------------------description------------------------
/ rrb 13Feb07 "macro called" message added
/ rrb 30Jul07 Header tidy
/ rrb 04May11 Code tidy
/ rrb 11Jan13 Header tidy. %lowcase removed from submacro list and
/ use of %qlowcase documented. %nrbquote() recommended in
/ place of %bquote() in Notes and Usage. Version number
/ unchanged as no change made to the macro code (v1.0)
/===============================================================================
/ This is public domain software. No guarantee as to suitability or accuracy is
/ given or implied. User uses this code entirely at their own risk.
/=============================================================================*/
%macro capmac(string,ignore=);
%local i igquote bit words;
%if %length(&ignore) %then %let igquote=%quotelst(&ignore);
%let words=%words(&string);
%do i=1 %to &words;
%let bit=%qscan(&string,&i,%str( ));
%if %length(&ignore) %then %do;
%if %index(&igquote,"%bquote(&bit)") %then %do;
&bit
%goto done;
%end;
%end;
%let bit=%qlowcase(&bit);
%*- One character word -;
%if %length(&bit) EQ 1 %then %do;
%if &i EQ 1 %then %do;
%qupcase(&bit)
%end;
%else %if "%bquote(&bit)" EQ "a" %then %do;
a
%end;
%else %do;
%qupcase(&bit)
%end;
%end;
%*- Longer than one character word -;
%else %do;
%*- always capitalise the first word -;
%if &i EQ 1 %then %do;
%qupcase(%substr(&bit,1,1))%qsubstr(&bit,2)
%end;
%*- leave join words as lower text if not the last word -;
%else %if %index("an" "and" "as" "at" "but" "by" "for" "in" "is" "it" "of"
"on" "or" "so" "that" "the" "to" "when" "with",
"%bquote(&bit)") and (&i LT &words) %then %do;
&bit
%end;
%*- all other cases -;
%else %do;
%qupcase(%substr(&bit,1,1))%qsubstr(&bit,2)
%end;
%end;
%done:
%end;
%mend capmac;
%macro changesep(
l= /* value list */
, lv= /* external variable override for value list */
, lsep=%str( ) /* separator between values */
, osep=%str(,) /* separator for rteurned list */
) ;
/* L (or &LV) is list of quoted items separated by LSEP
return unquoted list of items separated by OSEP
LV provides override to specify external variable name instead list.
If the LV option is used then L and CHG_: should be avoided for variable names.
examples:
%put %changesep ( l=a b c, lv= , lsep= %str( ), osep=%str(,) );
Credit:
source code from Ian Whitlock, Names, Names, Names - Make Me a List
(SGF 2007) http://www2.sas.com/proceedings/forum2007/052-2007.pdf
(SESUG 2008) http://analytics.ncsu.edu/sesug/2008/SBC-128.pdf
*/
%local chg_list ;
%if %length(&lv) = 0 %then
%let lv = l ;
%if %length(%superq(&lv)) > 0 %then
%do ;
%if %superq(osep)= %str( ) %then
%do ;
%let chg_list = %qsysfunc(strip(%superq(&lv))) ;
%let chg_list = %qsysfunc(compbl(&chg_list)) ;
%end ;
%else
%let chg_list = %superq(&lv) ;
%let chg_list = %qsysfunc(translate(&chg_list,&osep,&lsep)) ;
%end ;
%unquote(&chg_list)
%mend changesep ;
/*Retrieving the number of words in a macro variable*/
/* valid in SAS 9.1 and above. */
/*
http://support.sas.com/kb/26/152.html
*/
%macro countw(L);
%let countw=%sysfunc(countw(&L));
%eval(&countw);
%mend countw;
/*example
%put %countw(e 5 5);
*/
/*<pre><b>
/ Program : dequote.sas
/ Version : 1.0
/ Author : Roland Rashleigh-Berry (http://www.datasavantconsulting.com/roland/)
/ Date : 04-May-2011
/ Purpose : Function-style macro to remove front and end matching quotes
/ from a macro string and return the result.
/ SubMacros : %qdequote
/ Notes : This is a function-style macro that calls %qdequote and uses
/ %unquote to remove the macro quoting so that you can use it in
/ ordinary sas code.
/ Usage : %let str=%dequote(%qreadpipe(echo '%username%'));
/ %put %dequote(%qreadpipe(echo '%username%'));
/
/===============================================================================
/ PARAMETERS:
/-------name------- -------------------------description------------------------
/ str (pos) Macro string to dequote
/===============================================================================
/ AMENDMENT HISTORY:
/ init --date-- mod-id ----------------------description------------------------
/ rrb 04May11 Code tidy
/===============================================================================
/ This is public domain software. No guarantee as to suitability or accuracy is
/ given or implied. User uses this code entirely at their own risk.
/=============================================================================*/
%macro dequote(str);
%unquote(%qdequote(&str))
%mend dequote;
/*<pre><b>
/ Program : dir.sas
/ Version : 1.1
/ Author : Roland Rashleigh-Berry (http://www.datasavantconsulting.com/roland/)
/ Date : 26-Jun-2011
/ Purpose : Function-style macro to return a list of members of a directory
/ on a WINDOWS platform according to the file pattern you supply.
/ If you supply just the directory name then all members are
/ listed. This runs the MSDOS command in the form "dir /B mydir"
/ SubMacros : %qreadpipe
/ Notes : Just the file names are returned unquoted. If you need the full
/ path name in double quotes then use the %dirfpq macro instead
/ which will correctly handle file names containing spaces.
/ Usage : %let dirlist=%dir(C:\utilmacros);
/ %let dirlist=%dir(C:\utilmacros\*.sas);
/ %put dirlist=%dir(d:\test);
/===============================================================================
/ PARAMETERS:
/-------name------- -------------------------description------------------------
/ dir (pos) Directory path name (no quotes)
/===============================================================================
/ AMENDMENT HISTORY:
/ init --date-- mod-id ----------------------description------------------------
/ rrb 26Jun11 Remove quotes if supplied (v1.1)
/===============================================================================
/ This is public domain software. No guarantee as to suitability or accuracy is
/ given or implied. User uses this code entirely at their own risk.
/=============================================================================*/
%macro dir(dir);
%unquote(%qreadpipe(dir /B %sysfunc(dequote(&dir))))
%mend dir;
/*<pre><b>
/ Program : dirfpq.sas
/ Version : 1.1
/ Author : Roland Rashleigh-Berry (http://www.datasavantconsulting.com/roland/)
/ Date : 26-Jun-2011
/ Purpose : Function-style macro to return a list of full-path quoted members
/ of a directory on a Windows platform according to the file pattern
/ you supply.
/ SubMacros : %qreadpipe
/ Notes : Members are shown with the full path names in double quotes. If a
/ file name contains spaces then this will be correctly quoted. You
/ MUST give the full file pattern and not just the directory as this
/ does not use the DIR command to act on the directory but rather
/ expands the file pattern.
/ Usage : %let dirlist=%dirfpq(C:\utilmacros); %*- NO GOOD -;
/ %let dirlist=%dirfpq(C:\utilmacros\*); %*- GOOD -;
/ %let dirlist=%dirfpq(C:\utilmacros\*.sas); %*- GOOD -;
/ %put %dirfpq(d:\test\*.gif);
/===============================================================================
/ PARAMETERS:
/-------name------- -------------------------description------------------------
/ dir (pos) Directory path name with file pattern (no quotes)
/===============================================================================
/ AMENDMENT HISTORY:
/ init --date-- mod-id ----------------------description------------------------
/ rrb 26Jun11 Remove quotes if supplied (v1.1)
/===============================================================================
/ This is public domain software. No guarantee as to suitability or accuracy is
/ given or implied. User uses this code entirely at their own risk.
/=============================================================================*/
%macro dirfpq(dir);
%unquote(%qreadpipe(echo off & for %nrstr(%f) in (%sysfunc(dequote(&dir))) do echo "%nrstr(%f)"))
%mend dirfpq;
/*<pre><b>
/ Program : editlist.sas
/ Version : 1.0
/ Author : Roland Rashleigh-Berry (http://www.datasavantconsulting.com/roland/)
/ Date : 01-Nov-2012
/ Purpose : Function-style macro to allow you to edit a list of space
/ delimited items.
/ SubMacros : none
/ Notes : This macro is for tasks like generating rename statements where a
/ repeat of items in a list is required (see usage notes). The edit
/ string must be enclosed in single quotes. Elements of the list
/ are written to the macro variable "item" which can be referenced
/ in the edit string. If semicolons form part of the edit string
/ then for certain uses these can be protected using %nrstr().
/
/ If used in sas code you might need to %unquote() the final string.
/
/ This macro is essentially the same as the %doallitem macro but
/ giving a different usage emphasis and with no submacros.
/
/ Usage : %put >>> %editlist(aa bb cc dd,'&item=mr_&item');
/ %put >>> %editlist(xx_aa xx_bb xx_cc,
/ '&item=%substr(&item,4)');
/ %put >>> %editlist(xx_aa xx_bb xx_cc,
/ '%substr(&item,4)=&item%nrbquote(;)');
/
/ (will write to log:)
/ >>> aa=mr_aa bb=mr_bb cc=mr_cc dd=mr_dd
/ >>> xx_aa=aa xx_bb=bb xx_cc=cc
/ >>> aa=xx_aa; bb=xx_bb; cc=xx_cc;
/ %put >>> %editlist(aa bb cc dd,'&item=mr_&item');
/===============================================================================
/ PARAMETERS:
/-------name------- -------------------------description------------------------
/ list (pos) List of space delimited items
/ editstr (pos) Edit string (in single quotes)
/===============================================================================
/ AMENDMENT HISTORY:
/ init --date-- mod-id ----------------------description------------------------
/ rrb 31Oct12 New (v1.0)
/===============================================================================
/ This is public domain software. No guarantee as to suitability or accuracy is
/ given or implied. User uses this code entirely at their own risk.
/=============================================================================*/
%macro editlist(list,editstr);
%local i item;
%let i=1;
%let item=%scan(&list,&i,%str( ));
%do %while(%length(&item));
%sysfunc(dequote(&editstr))
%let i=%eval(&i + 1);
%let item=%scan(&list,&i,%str( ));
%end;
%mend editlist;
%macro for(macro_var_list,in=,do=);
/*
http://www.sascommunity.org/wiki/Streamlining_Data-Driven_SAS_With_The_%25FOR_Macro
http://www.wuss.org/proceedings08/08WUSS%20Proceedings/papers/app/app04.pdf
Function: This macro performs a loop generating SAS code. It
proceeds sequentially through one of 5 kinds of data objects:
SAS dataset, value list, number range, dataset contents and
directory contents. Data object values are assigned to macro
variables specified in macro_var_list upon each loop iteration.
Example:
%for(hospid hospname, in=[report_hosps], do=%nrstr(
title "&hospid &hospname Patient Safety Indicators";
proc print data=psi_iqi(where=(hospid="&hospid")); run;
))
The example above loops over the dataset "report_hosps", which
has dataset variables "hospid" and "hospname". For each dataset
observation, macro variables &hospid and &hospname are assigned
values from the identically named dataset variables and the loop
code is generated, which in the example prints a report.
Parameters:
macro_var_list = space-separated list of macro variable names
to be assigned values upon each loop iteration.
in = Data object to access. Object type is distinguished
by choice of brackets (or no backets for a range):
(a b c) - a space-separated value list whose
values are sequentially accessed.
[xyz] - a SAS dataset whose observations are
sequentially accessed.
{xyz} - a SAS dataset whose variable descriptions
(proc contents) are sequentially accessed.
<c:\abc> - a directory path whose file descriptions
are sequentially accessed.
1:100 - a number range whose values are
sequentially accessed.
do = The SAS code to be generated for each iteration of
the %for macro. If macro variable substitution is
to be done in the loop code (the typical case) enclose
the code in a %nrstr() macro call to defer macro
substitution to loop generation time.
For dataset [ ] iterations:
The dataset name can be qualified with a libname and where clause.
For each observation in the dataset, all macro variables in the
macro_var_list are assigned values of identically named dataset
variables and the "do=" SAS code is generated.
For dataset contents { } iterations:
The dataset name can be qualified with a libname.
For each variable in the dataset, the macro variables in the
macro_var_list are assigned values to describe the dataset
variable and the "do=" SAS code is generated. Valid names in
macro_var_list are "name", "type", "length", "format" and "label".
name - is set to the variable name
type - is set to 1 for numeric variables and 2 for
character variables.
format - is set to the variable format
length - is set to the variable length
label - is set to the variable label
For directory < > iterations:
For each file in the directory, the macro variables in the
macro_var_list are assigned values to describe a directory
file and the "do=" SAS code is generated. Valid names in
macro_var_list are "filepath", "filename", "shortname",
"extension", and "isdir".
filepath - full pathname of file
filename - filename with extension
shortname - filename without extension
extension - file extension
isdir - 1 if file is directory, else 0
For value list ( ) iterations:
Space is the default value separator. Enclose other separator
characters in nested parentheses, e.g., in=((|)Joe Jones|Al Smith)
The variables named in macro_var_list are assigned successive values
from the value list. When all variables are assigned, the "do=" SAS
code is generated. The process repeats until the end of value list is
reached. If the end of value list is reached before all variables in
macro_var_list are assigned values, then the iteration is terminated
without generating the "do=" code on the partially assigned variables
(the number of values in the value list should be a multiple of the
number of names in macro_var_list).
For range : iterations:
A range with 2 numbers uses a single colon and has an implied
increment of 1. For a range with 3 numbers (e.g., in=1:11:2),
the final number is the increment. The first variable in the
macro_var_list is assigned values as it would be by a
%do-%to-%by statement.
NOTE: Macro variable values obtained from datasets remain unquoted
when they contain only letters, digits, whitespace, '_' and '.',
otherwise they are quoted. Values obtained from value list are
always unquoted.
Author: Jim Anderson, UCSF, [email protected]
"Please keep, use and pass on the %for macro
with this authorship note. -Thanks "
Please send improvements, fixes or comments to Jim Anderson.
*/
%local _for_itid _for_ct _for_do _for_i _for_val1 _for_var1 _n_
_for_dir _for_var_num _for_in_first _for_in_last _for_in_length
_for_in_sep _for_in_values _for_in_more _for_extra;
%let _for_do=&do;
%if %eval(%index(&do,%nrstr(%if))+%index(&do,%nrstr(%do))) %then
%do; %* conditional macro code - need to embed in macro;
%global _for_gen;
%if &_for_gen=%str( ) %then %let _for_gen=0;
%else %let _for_gen=%eval(&_for_gen+1);
%unquote(%nrstr(%macro) _for_loop_&_for_gen(); &do %nrstr(%mend;))
%let _for_do=%nrstr(%_for_loop_)&_for_gen();
%end;
%let _for_ct=0;
%let _for_in_first=%qsubstr(&in,1,1);
%let _for_in_length=%length(&in);
%let _for_in_last=%qsubstr(&in,&_for_in_length,1);
%if &_for_in_first=%qsubstr((),1,1) %then
%do; %* loop over value list;
%if &_for_in_last ne %qsubstr((),2,1) %then
%do;
%put ERROR: "for" macro "in=(" missing terminating ")";
%return;
%end;
%if ¯o_var_list=%str( ) %then
%do; %*empty variable list - perhaps (s)he just wants &_n_;
%let macro_var_list=_for_extra;
%end;
%if %qsubstr(&in,2,1) ne &_for_in_first %then
%do; %* implicit space separator -- empty entries disallowed;
%if &_for_in_length<3 %then %return;
%let _for_in_values=%substr(&in,2,%eval(&_for_in_length-2));
%local _for_value_index;
%let _for_value_index=1;
%do %while(1);
%let _for_ct=%eval(&_for_ct+1);
%let _n_=&_for_ct;
%let _for_i=1;
%let _for_var1=%scan(¯o_var_list,1,%str( ));
%do %while(%str(&_for_var1) ne %str( ));
%let _for_val1=%scan(&_for_in_values,&_for_value_index,%str( ));
%let _for_value_index=%eval(&_for_value_index+1);
%if %length(&_for_val1)=0 %then
%do; %* end of values before end of variables, terminate iteration;
%return;
%end;
%let &_for_var1=&_for_val1;
%let _for_i=%eval(&_for_i+1);
%let _for_var1=%scan(¯o_var_list,&_for_i,%str( ));
%end;
%unquote(&_for_do)
%end;
%return;
%end;
%else
%do; %* explicit separator -- empty entries allowed;
%if &_for_in_length<6 %then %return; %* empty list;
%let _for_in_sep=%qsubstr(&in,3,1);
%if %qsubstr(&in,4,1) ne &_for_in_last %then
%do;
%put ERROR: "for" macro "in=" explicit separator missing right parenthesis;
%return;
%end;
%let _for_in_values=%qleft(%qtrim(%qsubstr(&in,5,%eval(&_for_in_length-5))));
%let _for_in_more=1;
%do %while(1);
%let _for_ct=%eval(&_for_ct+1);
%let _n_=&_for_ct;
%let _for_i=1;
%let _for_var1=%scan(¯o_var_list,1,%str( ));
%do %while(%str(&_for_var1) ne %str( ));
%if &_for_in_more=0 %then %return; %* end of value list;
%if &_for_in_sep=%qsubstr(&_for_in_values,1,1) %then %let &_for_var1=;
%else %let &_for_var1=%scan(&_for_in_values,1,&_for_in_sep);
%let _for_i=%eval(&_for_i+1);
%let _for_var1=%scan(¯o_var_list,&_for_i,%str( ));
%let _for_in_more=%index(&_for_in_values,&_for_in_sep);
%if %length(&_for_in_values)=&_for_in_more %then %let _for_in_values=%str( );
%else %let _for_in_values=%qsubstr(&_for_in_values,%eval(&_for_in_more+1));
%end;
%unquote(&_for_do)
%end;
%return;
%end;
%end;
%else %if &_for_in_first=%str([) %then
%do; %* loop over dataset;
%local _for_in_dataset;
%if &_for_in_last ne %str(]) %then
%do;
%put ERROR: "for" macro "in=[" missing terminating "]";
%return;
%end;
%if &_for_in_length<3 %then %return;
%let _for_in_dataset=%substr(&in,2,%eval(&_for_in_length-2));
%let _for_itid=%sysfunc(open(&_for_in_dataset));
%if &_for_itid=0 %then
%do;
%put ERROR: for macro cant open dataset &_for_in_dataset;
%return;
%end;
%do %while(%sysfunc(fetch(&_for_itid,NOSET))>=0);
%let _for_ct=%eval(&_for_ct+1);
%let _n_=&_for_ct;
%let _for_i=1;
%let _for_var1=%scan(¯o_var_list,1,%str( ));
%do %while(%str(&_for_var1) ne %str( ));
%let _for_var_num=%sysfunc(varnum(&_for_itid,&_for_var1));
%if &_for_var_num=0 %then
%do;
%put ERROR: "&_for_var1" is not a dataset variable;
%return;
%end;
%if %sysfunc(vartype(&_for_itid,&_for_var_num))=C %then
%do; %* character variable;
%let _for_val1=%qsysfunc(getvarc(&_for_itid,&_for_var_num));
%if %sysfunc(prxmatch("[^\w\s.]+",&_for_val1)) %then
%let &_for_var1=%qtrim(&_for_val1);
%else
%let &_for_var1=%trim(&_for_val1);
%end;
%else
%do; %* numeric variable;
%let &_for_var1=%sysfunc(getvarn(&_for_itid,&_for_var_num));
%end;
%let _for_i=%eval(&_for_i+1);
%let _for_var1=%scan(¯o_var_list,&_for_i,%str( ));
%end;
%unquote(&_for_do)
%end;
%let _for_i=%sysfunc(close(&_for_itid));
%return;
%end;
%else %if &_for_in_first=%str({) %then
%do; %* loop over proc contents;
%local _for_in_dataset;
%if &_for_in_last ne %str(}) %then
%do;
%put ERROR: "for" macro "in={" missing terminating "}";
%return;
%end;
%if &_for_in_length<3 %then %return;
%let _for_in_dataset=%substr(&in,2,%eval(&_for_in_length-2));
%let _for_itid=%sysfunc(open(&_for_in_dataset));
%if &_for_itid=0 %then
%do;
%put ERROR: for macro cant open dataset &_for_in_dataset;
%return;
%end;
%let _for_ct = %sysfunc(attrn(&_for_itid,NVARS));
%do _for_i=1 %to &_for_ct;
%let _n_=&_for_i;
%let _for_var_num=1;
%let _for_var1=%upcase(%scan(¯o_var_list,1,%str( )));
%do %while(%str(&_for_var1) ne %str( ));
%if &_for_var1=NAME %then
%do;
%let name=%sysfunc(varname(&_for_itid,&_for_i));
%end;
%else %if &_for_var1=FORMAT %then
%do;
%let format=%sysfunc(varfmt(&_for_itid,&_for_i));
%end;
%else %if &_for_var1=TYPE %then
%do;
%if %sysfunc(vartype(&_for_itid,&_for_i))=C %then
%let type=2;
%else
%let type=1;
%end;
%else %if &_for_var1=LENGTH %then
%do;
%let length=%sysfunc(varlen(&_for_itid,&_for_i));
%end;
%else %if &_for_var1=LABEL %then
%do;
%let _for_val1=%qsysfunc(varlabel(&_for_itid,&_for_i));
%if %sysfunc(prxmatch("[^\w\s.]+",&_for_val1)) %then
%let label=%qtrim(&_for_val1);
%else
%let label=%trim(&_for_val1);
%end;
%else
%do;
%put ERROR: "&_for_var1" is not NAME, TYPE, FORMAT, LENGTH or LABEL;
%return;
%end;
%let _for_var_num=%eval(&_for_var_num+1);
%let _for_var1=%upcase(%scan(¯o_var_list,&_for_var_num,%str( )));
%end;
%unquote(&_for_do)
%end;
%let _for_i=%sysfunc(close(&_for_itid));
%return;
%end;
%else %if &_for_in_first=%str(<) %then
%do; %* loop over directory contents;
%if &_for_in_last ne %str(>) %then
%do;
%put ERROR: "for" macro "in=<" missing terminating ">";
%return;
%end;
%let _for_val1=;
%if &_for_in_length<3 %then %return;
%let _for_dir=%substr(&in,2,%eval(&_for_in_length-2));
%let _for_itid=%sysfunc(filename(_for_val1,&_for_dir));
%let _for_itid=%sysfunc(dopen(&_for_val1));
%if &_for_itid=0 %then
%do;
%put ERROR: cant open directory path=&_for_dir;
%return;
%end;
%let _for_ct = %sysfunc(dnum(&_for_itid));
%do _for_i=1 %to &_for_ct;
%let _n_=&_for_i;
%let _for_var_num=1;
%let _for_var1=%upcase(%scan(¯o_var_list,1,%str( )));
%do %while(%str(&_for_var1) ne %str( ));
%let _for_extra=%sysfunc(dread(&_for_itid,&_for_i));
%if &_for_var1=FILENAME %then
%do;
%let filename=&_for_extra;
%end;
%else %if &_for_var1=EXTENSION %then
%do;
%if %index(&_for_extra,%str(.)) ne 0 %then
%do;
%let extension=.%scan(&_for_extra,-1,%str(.));
%end;
%else
%do;
%let extension=;
%end;
%end;
%else %if &_for_var1=FILEPATH %then
%do;
%let filepath=&_for_dir\&_for_extra; %*windows specific;
%end;
%else %if &_for_var1=SHORTNAME %then
%do;
%if %index(&_for_extra,%str(.)) ne 0 %then
%do;
%let _for_val1=%eval(%length(&_for_extra)-
%length(%scan(&_for_extra,-1,%str(.)))-1);
%let shortname=%substr(&_for_extra,1,&_for_val1);
%end;
%else
%do;
%let shortname=&_for_extra;
%end;
%end;
%else %if &_for_var1=ISDIR %then
%do; %*below windows specific;
%let _for_var1=_forfile;
%let _for_val1=%sysfunc(filename(_for_var1,&_for_dir\&_for_extra));
%let _for_val1=%sysfunc(dopen(&_for_var1));
%let isdir=%eval(&_for_val1 ne 0);
%if &isdir %then
%do;
%let _for_val1=%sysfunc(dclose(&_for_val1));
%end;
%end;
%else
%do;
%put ERROR: "&_for_var1" is not FILENAME, EXTENSION, FILEPATH, SHORTNAME or ISDIR;
%return;
%end;
%let _for_var_num=%eval(&_for_var_num+1);
%let _for_var1=%upcase(%scan(¯o_var_list,&_for_var_num,%str( )));
%end;
%unquote(&_for_do)
%end;
%let _for_i=%sysfunc(dclose(&_for_itid));
%let _for_i=%sysfunc(filename(_for_val1,));
%return;
%end;
%else %if %index(&in,%str(:)) %then
%do; %* loop from:to:by;
%local _for_in_from _for_in_to _for_in_by;
%let _for_in_from=%scan(&in,1,%str(:));
%let _for_in_to=%scan(&in,2,%str(:));
%if &_for_in_to=%str( ) %then
%do;
%put ERROR: for macro missing value after : in range;
%return;
%end;
%let _for_in_by=%scan(&in,3,%str(:));
%if &_for_in_by=%str( ) %then %let _for_in_by=1;
%let _for_var1=%scan(¯o_var_list,1,%str( ));
%let _for_ct=1;
%do _for_i=&_for_in_from %to &_for_in_to %by &_for_in_by;
%let _n_=&_for_ct;
%if %str(&_for_var1) ne %str( ) %then %let &_for_var1=&_for_i;
%let _for_ct=%eval(&_for_ct+1);
%unquote(&_for_do)
%end;
%return;
%end;
%put ERROR: for macro unrecognized in= argument value "&in";
%mend for;/*
Purpose: return the list of variables in a data set
Examples:
%put %getVar(%str(sashelp.class));
%put %getVar(%str(sashelp.class),n);
%put %getVar(%str(sashelp.class),N);
%put %getVar(%str(sashelp.class),c);
%put %getVar(%str(sashelp.class),C);
Credits:
Source code by Arthur Carpenter, Storing and Using a List of Values in a Macro Variable
http://www2.sas.com/proceedings/sugi30/028-30.pdf
Authored by Michael Bramley
Jiangtang Hu (2013, Jiangtanghu.com) adds variable type (N, C) options.
updated in http://www.sascommunity.org/wiki/Macro_VarList
*/
%macro getVar(dset,type) ;
%local varlist ;
%let fid = %sysfunc(open(&dset)) ;
%if &fid %then %do ;
%do i=1 %to %sysfunc(attrn(&fid,nvars)) ;
%if %upcase(&type) = N %then %do;
%if %sysfunc(vartype(&fid,&i)) = N %then
%let varlist= &varlist %sysfunc(varname(&fid,&i));
%end;
%else %if %upcase(&type) = C %then %do;
%if %sysfunc(vartype(&fid,&i)) = C %then
%let varlist= &varlist %sysfunc(varname(&fid,&i));
%end;
%else
%let varlist= &varlist %sysfunc(varname(&fid,&i));
%end ;
%let fid = %sysfunc(close(&fid)) ;
%end ;
&varlist
%mend getVar ;
/*
%put %get_label(sashelp.iris,SepalLength);
*/
%macro get_label(data,variable);
%local label;
%let dsid = %sysfunc(open(&data));
%if &dsid %then %do;
%let label=%sysfunc(varlabel(&dsid,%sysfunc(varnum(&dsid,&variable))));
%let rc = %sysfunc(close(&dsid));
%end;
&label;
%mend;
/*<pre><b>
/ Program : match.sas
/ Version : 2.0
/ Author : Roland Rashleigh-Berry (http://www.datasavantconsulting.com/roland/)
/ Date : 03-Dec-2012
/ Purpose : Function-style macro to return elements of a list that match those
/ in a reference list.
/ SubMacros : %words %nodup
/ Notes : Non-matching list elements are returned in the global macro
/ variable _nomatch_ .
/ Usage : %let match=%match(aa bb,aa cc);
/ %put %match(aa bb,aa cc);
/
/===============================================================================
/ PARAMETERS:
/-------name------- -------------------------description------------------------
/ ref (pos) Space-delimited reference list
/ list (pos) Space-delimited list
/ nodup=yes By default, remove duplicates from the list
/ casesens=no By default, case sensitivity is not important.
/ fixcase=no By default, do not make the case of matching items the same
/ as the item in the reference list.
/===============================================================================
/ AMENDMENT HISTORY:
/ init --date-- mod-id ----------------------description------------------------
/ rrb 19Mar07 Macro called message added plus header tidy
/ rrb 30Jul07 Header tidy
/ rrb 01May11 Code restructured and missing list allowed (v2.0)
/ rrb 03Dec12 Header tidy (%nodup added to submacro list)
/===============================================================================
/ This is public domain software. No guarantee as to suitability or accuracy is
/ given or implied. User uses this code entirely at their own risk.
/=============================================================================*/
%macro match(ref,list,nodup=yes,casesens=no,fixcase=no);
%local err errflag list2 nref nlist i j item match refitem;
%let err=ERR%str(OR);
%let errflag=0;
%global _nomatch_;
%let _nomatch_=;
%if not %length(&nodup) %then %let nodup=yes;
%if not %length(&casesens) %then %let casesens=no;
%if not %length(&fixcase) %then %let fixcase=no;
%let nodup=%upcase(%substr(&nodup,1,1));
%let casesens=%upcase(%substr(&casesens,1,1));
%let fixcase=%upcase(%substr(&fixcase,1,1));
%if "&nodup" EQ "Y" %then %let list2=%nodup(&list,casesens=&casesens);
%else %let list2=&list;
%let nref=%words(&ref);
%let nlist=%words(&list2);
%if not &nref %then %do;
%put &err: (match) No elements in reference list;
%let errflag=1;
%end;
%if &errflag %then %goto exit;
%if not &nlist %then %goto skip;
%do i=1 %to &nlist;
%let item=%scan(&list2,&i,%str( ));
%let match=NO;
%do j=1 %to &nref;
%let refitem=%scan(&ref,&j,%str( ));
%if "&casesens" EQ "N" %then %do;
%if "%upcase(&item)" EQ "%upcase(&refitem)" %then %do;
%let match=YES;
%let j=&nref;
%end;
%end;
%else %do;
%if "&item" EQ "&refitem" %then %do;
%let match=YES;
%let j=&nref;
%end;
%end;
%end;
%if &match EQ YES %then %do;
%if "&fixcase" EQ "N" %then &item;
%else &refitem;
%end;
%else %let _nomatch_=&_nomatch_ &item;
%end;
%goto skip;
%exit: %put &err: (match) Leaving macro due to problem(s) listed.;
%skip:
%mend match;
/*http://listserv.uga.edu/cgi-bin/wa?A2=ind9907C&L=sas-l&P=R1337
Dorfman:
%LET LIST =
SG FJLKDSN GEWO OPITHUI GJSERO TNJEOWIJ TW9345Y TWES SDJGJSRL NWOITJN RET
POTREPOR _5TWT WPST NWP4 T924YW P9YTP9W4 NT599P DLKFGBLK SDGSGIW A AEG AEF ZG
EGH A G HA HESH AIT4Y8W3 HAW T83PTQ3Y O OYTP53YT PQYP8Y3Q SSLKGH SLIEUH AERH
DQLUEIUR SL SLSHIH4 AEK AH5WO TA AEH EU DJGLKDJ ERHISHKL QLR UHER GHSLHLSH
RBGHSD SLH SKEHRT RSKIEHB Q87O3WSL B SDKLQI WPE WEGIUQ HIHQPIG H QPGKLXK ZLQA
HQP GTHQPG Z AOIRPH PGT3Q PGHSE QAPUR HPQYPQ A XC N SLKG PZEAF RQIUH RS H
T38753QO SL KG OW7TY OQ HSL QP YOQ287 _W7 TOQR TL DSLSD YSIUYG RISWYG VQ369R4
ORA47Q3 Y94 Z Q374R R462QTQ;
%put %MLSORT2 (SORTIN=&LIST,SEQ=A,NODUP=N);