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;

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;

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;

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, &REGEXP); === */ %macro ReListDir(DIRNAME, DATASET, REGEXP); %let DIRNAME = %sysfunc(compress(&DIRNAME, '"')); %let DATASET = %sysfunc(compress(&DATASET, '"')); %let REGEXP = %sysfunc(compress(&REGEXP, '"')); %ListDir(&DIRNAME, &DATASET); proc sql noprint; select count(*) into :CNT from &DATASET ; quit; data &DATASET; set &DATASET; if _n_ = 1 then Pattern = prxparse("&REGEXP"); 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