2013-07-17 41 views
1

我想在%let調用中使用宏,下面是宏代碼以及我想如何調用它。請幫我實現它。如何在%let中使用SAS宏調用

%macro xscan(string, delimiter, word_number); 

%let len1=%length(&string); /*Computing the length of the string*/ 
%let len=%eval(&len1+1); 
%let sub=%scan(&string,&word_number,"&delimiter"); /*Fetch the string specified by  word_number*/ 

%if &word_number ge 0 %then %do; 
%let pos=%index(&string,&sub); /* Locate the position while reading left to right*/ 
%end; 

%if &word_number lt 0 %then %do; 
data _null_; 
pos=find("&string","&sub",-&len); /* Locate the position while reading from right to left*/ 
call symput("pos",pos); 
run; 
%end; 

%let strg=%substr(&string,&pos); /* Extract the substring*/ 

%put the string is &strg; 
%mend; 

%let sub_str = %xscan(a bb ccc dddd bb eeeee, %str(), -2); 
%put The value of sub_str = &sub_str; 

期望的實現:

data work.in_data; 
length in_string $50; 
in_string = 「a bb ccc dddd bb eeeee」; 
output; 
in_string = 「aa b cc aa dee」; 
output; 
    run; 

    data work.out_data; 
set work.in_data; 
length sub_str $50; 
start_word_num = -(_n_ +1); 
sub_str = %xscan(in_string,’ ‘, start_word_num); 
    run; 

    proc print; run; 
+0

給出了一些代碼,但問題的本質並不明確。請澄清你的問題。 – CSJ

+0

呃,它可能會更清晰,但問題標題其實很清晰(而且是問題)給SAS程序員。 – Joe

回答

1

我發佈了一個新答案,因爲另一個答案回答了一個稍微不同的問題。

在這裏,你的宏真的是要執行數據步技術,而不是宏技術。你不能(很容易)使用宏來編輯變量內容;一個宏旨在編寫SAS代碼,而不是修改變量。你可以使用PROC FCMP來解決這個問題,如果我有更多的時間,我可能會這樣做,但現在這裏只有數據步驟技術和正常(非功能性)宏的正確解決方案。

首先,編寫數據步驟技術來完成它。這是一個相當混亂但有效的解決方案。它只適用於負的start_word_num;如果需要左或右,則需要對循環參數進行一些修改。我建議以此爲出發點,並根據您的需求進行改進。

data work.out_data; 
set work.in_data; 
length sub_str $50; 
start_word_num = -(_n_ +1); 
do _t = countc(trimn(in_string),' ')+1 to countc(trimn(in_string),' ')+start_word_num+2 by -1; 
    sub_str = catx(' ',scan(in_string,_t,' '),sub_str); 
    put _t= sub_str=; 
end; 
put in_string= sub_str=; 
run; 

現在,將循環移入宏。

%macro xscan(word_num, initial_string, result); 
&result.=' '; 
do _t = countc(trimn(&initial_string.),' ')+1 to countc(trimn(&initial_string.),' ')+&word_num.+2 by -1; 
    &result. = catx(' ',scan(&initial_string.,_t,' '),&result.); 
end; 
%mend xscan; 


data work.out_data; 
set work.in_data; 
length sub_str $50; 
start_word_num = -(_n_ +1); 
%xscan(start_word_num,in_string,sub_str); 
put in_string= sub_str=; 
run; 
+0

再次感謝喬 – ElBaronRojo

1

你有兩個問題。首先,函數樣式的宏不能包含任何數據步驟(或者proc或其他)。如果您確實需要執行數據步驟,則必須使用帶有run_macro的FCMP。但是,在這裏,您可以使用%SYSFUNC來完成您在數據步驟中所做的操作。

其次,您需要實際返回值。最終宏解析爲文本,所以你需要解決

%let x = %xscan(...); 

%let x = bb eeeee; 

所以,你需要根本就BB在宏EEEEE作爲開放的文本。

這應該做到兩件事:

options mprint symbolgen; 

%macro xscan(string, delimiter, word_number); 
%local len1 len sub pos; 

%let len1=%length(&string); /*Computing the length of the string*/ 
%let len=%eval(&len1+1); 
%let sub=%scan(&string,&word_number,"&delimiter"); /*Fetch the string specified by  word_number*/ 

%if &word_number ge 0 %then %do; 
%let pos=%index(&string,&sub); /* Locate the position while reading left to right*/ 
%end; 

%else %if &word_number lt 0 %then %do; 
%let pos=%sysfunc(find(&string,&sub,-&len)); /* Locate the position while reading from right to left*/ 
%end; 

%substr(&string,&pos) /* Extract the substring*/ 

%mend; 

%let sub_str = %xscan(a bb ccc dddd bb eeeee, %str(), -2); 
%put The value of sub_str = &sub_str; 

(注意,我不一定知道這樣做你真正想要的,但它確實會出現什麼樣的代碼做的事情。)

一些提示函數風格的宏,羅布Penridge的禮貌:

  1. 使用像這樣一%的本地聲明中定義的所有宏變量:%本地LEN1 len個子POS ;.這樣你就不會覆蓋全局宏變量。
  2. 使用/ *此樣式用於重新打開* /。使用其他評論樣式可能會導致該行結束。
  3. 使宏工作的祕訣是在最後使用%substr的行。這解決了bb eeeeee留在了開放代碼中。既然這就剩下了,那就是調用宏解決的問題。
  4. 請勿在實際返回的行上放置分號,因爲使用函數式宏時可能不合需要。
+0

好的回答喬。這些新功能宏的一些技巧。 1)使用'%local'語句定義所有的宏變量,例如:'%local len1 len sub pos;'。 2)請注意Joe已經使用了'/ *這種風格來提醒* /'。使用其他評論風格可能有probs。 3)讓宏工作的祕密是Joe使用'%substr'的​​行。這解決了'bb eeeeee'留在了開放代碼中。既然這就剩下了,那就是調用宏解決的問題。 4)@Joe你可能想要刪除這條線上的冒號,因爲技術上冒號也會返回,你不想要。 –

+0

謝謝喬的答案它確實有效。你能幫我多做一件事,比方說,在下面的數據步驟中使用相同的宏,需要做些什麼修改。 data work.in_data; \t長度in_string $ 50; \t in_string =「a bb ccc dddd bb eeeee」; \t輸出; \t in_string =「aa b cc aa dee」; \t輸出; 跑; data work.out_data; \t set work.in_data; \t長度sub_str $ 50; \t start_word_num = - (_ n_ +1); \t sub_str =%xscan(in_string,'',start_word_num); 跑; proc print;跑; – ElBaronRojo

+0

謝謝@RobPenridge,註冊! – Joe