11 sierpnia 2009
Rekurencyjne wypisywanie zawartości katalogu -- SAS 4GL
Na tej stronie znalazłem kod makra w języku 4GL służącego do wypisywania rekurencyjnie zawartości katalogów. Zmodyfikowałem to makro tak, aby lepiej odpowiadało moim potrzebom. Dodałem możliwość ograniczania głębokości rekurencji
%macro DirWalk(DIRNAME, MAXDEPTH=-1);
%local I FILEREF RC DIRID FILESCNT LEVEL LEN;
%let DIRNAME = %sysfunc(translate(&DIRNAME, "/", "\"));
%let DIRNAME = %sysfunc(compress(&DIRNAME, '"'));
%let LEN = %sysfunc(length(&DIRNAME));
%let LAST = %sysfunc(substr(&DIRNAME, &LEN, 1));
%if "&LAST" = "/" %then
%let DIRNAME = %sysfunc(substr(&DIRNAME, 1, &LEN - 1));
%let LEVEL = %eval(&MAXDEPTH);
%if %sysfunc(symexist(DEPTH)) = 0 %then
%let DEPTH = 1;
%let RC = %sysfunc(filename(FILEREF, "&DIRNAME"));
%let DIRID = %sysfunc(dopen(&FILEREF));
%if &DIRID > 0 %then %do;
* seems to be a directory, so walk it;
%let FILESCNT = %sysfunc(dnum(&DIRID));
%if &FILESCNT > 0 %then %do;
%do I = 1 %to &FILESCNT;
%let NAME =
%sysfunc(trim(&DIRNAME/%sysfunc(dread(&DIRID, \
&I))));
%put &DEPTH &LEVEL &I &NAME;
%if &LEVEL ne 0 %then %do;
%let DEPTH = %eval(&DEPTH + 1);
%dirWalk("&NAME", \
MAXDEPTH=%sysfunc(max(&LEVEL - 1, -1)));
%let DEPTH = %eval(&DEPTH - 1);
%end;
%end;
%end;
%let RC = %sysfunc(dclose(&DIRID));
%end;
%mend DirWalk;
Makro o można wywoływać na kilka sposobów:
%DirWalk("C:/katalog/", MAXDEPTH=0);
%DirWalk("C:/katalog/", MAXDEPTH=1);
%DirWalk("C:/katalog/", MAXDEPTH=-1);
%DirWalk("C:/katalog/");
Pierwsze wywołanie spowoduje wypisanie jedynie zawartości katalogu "C:/katalog/". Po drugim wywołaniu zobaczymy zawartość podanego katalogu oraz katalogów bezpośrednio w nim się znajdujących. Ostatnie dwa wywołania są równoważne i powodują wypisania zawartości podanego katalogu oraz wszystkich podkatalogów w nim znajdujących niezależnie od głębokości na której są położone w drzewie katalogów.
Samo wypisywanie zawartości katalogu jest mało przydatne. O wiele większą korzyść można odnieść z listy plików i katalogów zapisanych w tablicy. Służy temu kolejne makro (na uwagę zasługuje makro w nim zagnieżdżone):
%macro ListRecursive(DATASET, DIRNAME, MAXDEPTH=-1);
%let DIRNAME = &DIRNAME;
%let DATASET = &DATASET;
%macro DataDirWalk(DIRNAME, MAXDEPTH=-1);
%local I FILEREF RC DIRID FILESCNT LEVEL LEN;
%let DIRNAME = %sysfunc(translate(&DIRNAME, "/", "\"));
%let DIRNAME = %sysfunc(compress(&DIRNAME, '"'));
%let LEN = %sysfunc(length(&DIRNAME));
%let LAST = %sysfunc(substr(&DIRNAME, &LEN, 1));
%if "&LAST" = "/" %then
%let DIRNAME = %sysfunc(substr(&DIRNAME, 1, &LEN - 1));
%let LEVEL = %eval(&MAXDEPTH);
%if %sysfunc(symexist(DEPTH)) = 0 %then
%let DEPTH = 1;
%let RC = %sysfunc(filename(FILEREF, "&DIRNAME"));
%let DIRID = %sysfunc(dopen(&FILEREF));
%if &DIRID > 0 %then %do;
%let FILESCNT = %sysfunc(dnum(&DIRID));
%if &FILESCNT > 0 %then %do;
%do I = 1 %to &FILESCNT;
%let NAME = %sysfunc(dread(&DIRID, &I));
%let PATH = %sysfunc(trim(&DIRNAME/&NAME));
fileNum = &I;
fileName = "&NAME";
filePath = "&PATH";
parentDir = "&DIRNAME";
depth = &DEPTH;
output;
%if &LEVEL ne 0 %then %do;
%let DEPTH = %eval(&DEPTH + 1);
%DataDirWalk("&PATH", \
MAXDEPTH=%sysfunc(max(&LEVEL-1, -1)));
%let DEPTH = %eval(&DEPTH - 1);
%end;
%end;
%end;
%let RC = %sysfunc(dclose(&DIRID));
%end;
%mend DataDirWalk;
data &DATASET;
format fileName $32.;
format filePath $128.;
format parentDir $96.;
format depth best4.;
format fileNum best8.;
%DataDirWalk(&DIRNAME, MAXDEPTH=&MAXDEPTH);
run;
%mend;
- DirWalk.sas --- kod makra %DirWalk
- ListRecursive.sas --- kod makra %ListRecursive
Słowa kluczowe: sas, 4GL, makra
15 lipca 2009
Tworzenie listy tablic -- SAS
Poniżej zamieszczam kod makra SAS, które służy tworzeniu listy tablic.
Lista tablic jest tworzona w oparciu o dopasowanie nazw biblioteki i tablicy do zadanych wzorców (wyrażenia regularne). Domyślnie makro nie pobiera jedynie nazwę wynikowego zbioru/tablicy. W takim przypadku działanie makra sprowadza się do skopiowania tablicy sashelp.vstable, która zawiera pary biblioteka x tablica. Zawężenie zbioru tablic można uzyskać podając wzorce zapisane za pomocą wyrażeń regularnych, do którego ma pasować nazwa tablicy i/lub nazwa biblioteki, w której znajduje się tablica.
Opis konstrukcji wyrażeń regularnych w SAS można znaleźć w dokumencie An Introduction to Perl Regular Expressions in SAS 9 [pdf, 489 kB].
Korzystając z zamieszczoneg niżej makra należy pamiętać o tym, że wszystkie nazwy bibliotek i tablic dostępne w widoku sashelp.vstable zapisywane są wyłącznie przy użyciu wielkich liter. Oznacza to, że fragmenty nazw zawarte w wyrażeniu regularnym powinny być również pisane wielką literą niezależnie od sposobu ich wyświetlania przez system SAS oraz zapisu w kodzie. Innym rozwiązaniem jest stworzenie wzorca, który jest niewrażliwy na wielkość liter. Wzorce takie tworzy się poprzez dodanie na końcu pojedynczej litery i (por. tekst komentarza w kodzie poniżej).
%macro ListTables(DATASET, LIBRE="/^./", TBLRE="/^./");
data &DATASET;
set sashelp.vstable;
if _n_ = 1 then do;
LibraryPattern = prxparse(&LIBRE);
TablePattern = prxparse(&TBLRE);
end;
retain LibraryPattern;
retain TablePattern;
fitsLibraryPattern =
prxmatch(LibraryPattern, strip(Libname));
fitsTablePattern =
prxmatch(TablePattern, strip(Memname));
if fitsLibraryPattern and fitsTablePattern;
keep
libname
memname
;
run;
%mend;
- ListTables.sas -- kod makra do pobrania [1 kB]
Słowa kluczowe: sas, 4GL, makra, regexp, wyrażenia regularne
08 lipca 2009
Tworzenie katalogu -- SAS
Poniżej zamieszczam kod makra SAS, które służy tworzeniu katalogów.
/* ====
CREATEDIR(DIRNAME)
Tworzy katalog DIRNAME np.
%CreateDir("C:\katalog");
==== */
%macro CreateDir(DIR_NAME);
options noxwait;
%let DIR_NAME = %sysfunc(compress(&DIR_NAME, '"'));
%put "&DIR_NAME";
data _null_;
d_name = '"' || "&DIR_NAME" || '"';
rc = filename('f_ref', d_name);
if not fexist('f_ref') then
call system('md ' || d_name);
run;
%mend;
Słowa kluczowe: sas, 4GL, makra
02 lipca 2009
Zamiana tenoru na datę zapadalności -- SAS
/* ====
MATURITYFROMTENOR(DATASET, REFDATE)
w tablicy DATASET tworzy kolumne MaturityDate na podstawie
danych w kolumnach Tenor i REFDATE
np. %MaturityFromTenor(tName, refDate);
MATURITYFROMTENOR(DATASET, REFDATE, TCOL=T_COL)
w tablicy DATASET tworzy kolumne MaturityDate na podstawie
danych w kolumnach "T_COL" i REFDATE
np. %MaturityFromTenor(tName, refDate, TCOL=Tenor);
MATURITYFROMTENOR(DATASET, REFDATE, TCOL=T_COL, MCOL=M_COL)
w tablicy DATASET tworzy kolumne "M_COL" na podstawie
danych w kolumnach "T_COL" i REFDATE
np. %MaturityFromTenor(tName, rDate, TCOL=tnr, MCOL=mDate);
REFDATE moze byc zarowno nazwa kolumny z data referencyjna
jak i sama data referencyjna
np.
%MaturityFromTenor(Maturity, ReferenceDate); - data
referencyjna w kolumnie ReferenceDate
%MaturityFromTenor(Maturity, "26mar2008"d); - data
referencyjna 26/03/2008
==== */
%macro MaturityFromTenor(DATASET, REFDATE, TCOL=Tenor,
MCOL=MaturityDate);
%let TCOL = %sysfunc(compress(&TCOL, '"'));
%let MCOL = %sysfunc(compress(&MCOL, '"'));
%let DATASET = %sysfunc(compress(&DATASET, '"'));
%let REFDATE = &REFDATE;
data &DATASET;
set &DATASET;
if _n_ = 1 then isTenorPattern =
prxparse("/^\d+[ ]*((D(|ay(|s)))|(W(|eek(|s)))|
(M(|onth(|s)))|(Y(|ear(|s))))$/i");
if _n_ = 1 then tUnitPattern =
prxparse("/((D(|ay(|s)))|(W(|eek(|s)))|(M(|onth(|s)))|
(Y(|ear(|s))))$/i");
if _n_ = 1 then nUnitPattern =
prxparse("/^\d+/");
retain isTenorPattern;
retain tUnitPattern;
retain nUnitPattern;
&TCOL = upcase(&TCOL);
isTenor = prxmatch(isTenorPattern, strip(&TCOL));
if %left(Tenor, 2) = "ON" then &MCOL = &REFDATE + 1;
if %left(Tenor, 2) = "SW" then &MCOL = &REFDATE + 7;
if isTenor then do;
call prxsubstr(tUnitPattern, strip(&TCOL),
tUnitStart, tUnitLength);
call prxsubstr(nUnitPattern, strip(&TCOL),
nUnitStart, nUnitLength);
/* implicit string to number conversion */
nUnits = substr(&TCOL, nUnitStart, nUnitLength) * 1;
if substr(&TCOL, tUnitStart, 1) = "D" then
&MCOL = &REFDATE + nUnits;
else if substr(&TCOL, tUnitStart, 1) = "W" then
&MCOL = &REFDATE + 7*nUnits;
else do;
referenceDay = day(&REFDATE);
referenceMonth = month(&REFDATE);
referenceYear = year(&REFDATE);
if substr(Tenor, tUnitStart, 1) = "M" then
referenceMonth = referenceMonth + nUnits;
if substr(Tenor, tUnitStart, 1) = "Y" then
referenceYear = referenceYear + nUnits;
if referenceMonth > 12 then do;
referenceYear = referenceYear +
(referenceMonth - mod(referenceMonth - 1, 12) - 1)
/ 12;
referenceMonth = mod(referenceMonth - 1, 12) + 1;
end;
&MCOL = mdy(referenceMonth, referenceDay,
referenceYear);
end;
end;
drop
referenceDay
referenceMonth
referenceYear
isTenorPattern
tUnitPattern
nUnitPattern
isTenor
tUnitStart
tUnitLength
nUnitStart
nUnitLength
nUnits
;
run;
%mend;
- MaturityFromTenor.sas -- plik z kodem źródłowym
Słowa kluczowe: makra, sas, 4GL
12 czerwca 2009
Zawartość katalogu i wyrażenia regularne -- SAS
Tutaj opisałem, jak można stworzyć tablicę zawierającą listę plików znajdujących się w zadanym katalogu. Często jednak zdarza się, że nie wszystkie pliki znajdujące się w danym katalogu powinny trafić do takego zbioru. Rozwiązanie może polegać na wczytaniu listy wszystkich plików oraz odrzuceniu tych, których nazwy nie spełniają zadanego wzorca. Można tego dokonać posługując się np. wyrażeniami regularnymi.
Poniżej przedstawiam fragment kodu makra (SAS) filtrujacy zapisywaną do tablicy zawartość zbioru wg dopasowania do zadanego wyrażenia regularnego.
/* ====
%let DIRNAME = "C:\katalog\";
%let DATASET = Listing;
%let REGEXP = "/xl[as]$/i";
%ReListDir(&DIRNAME, &DATASET, ®EXP);
=== */
%macro ReListDir(DIRNAME, DATASET, REGEXP);
%let DIRNAME = %sysfunc(compress(&DIRNAME, '"'));
%let DATASET = %sysfunc(compress(&DATASET, '"'));
%let REGEXP = %sysfunc(compress(®EXP, '"'));
%ListDir(&DIRNAME, &DATASET);
proc sql noprint;
select count(*) into :CNT
from &DATASET
;
quit;
data &DATASET;
set &DATASET;
if _n_ = 1 then Pattern = prxparse("®EXP");
retain Pattern;
Match = prxmatch(Pattern, strip(f_name));
if Match then call
prxsubstr(Pattern, strip(f_name), Start, Length);
if Match;
drop
Pattern
Match
;
run;
%mend;Słowa kluczowe: sas, 4GL, makra, regexp, wyrażenia regularne


![[vim created]](./grafika/vim_created.png)