曾在用K函數處理中文字串文章中提及專門用來處理中文的K函數,但沒有實際的例子,最近發生了一個案例,把處理心得分享給大家參考。
原問題為,想把地址中的某一條路刪除。
例如:
台北市中山路50號 → 台北市50號
北市板橋區中山路二段 → 北市板橋區二段
這樣的取代如果用EXCEL或WORD不難處理,但在SAS中似乎不是那麼人性。
以下程式我不會特別說明語法的指令,有興趣者可請自行研究或連至我推薦的網頁查詢。
先建立練習用檔案。
data a;
format text $50.;
input text $;
cards;
台北市中山路50號
台北市中正路50號
台北市中山山路50號
台北市中正北路50號
北市板橋區中山路二段
桃園市中壢區建國路1號
;
先用眼睛判斷的話,第1筆和第5筆地址中的「中山路」要刪除,而第3筆的「中山山路」則應保留。
我用了一個稍微複雜的判斷式處理,程式在下面。
data b;
set a;
format text1 $50.;
if kindex(text,"中山路")>=1 then do;
text1=kcompress(KUPDATE(text,kindex(text,"中山路"),3,""));
chk=1;
end;
else text1=text;
run; proc print data=b;
run;
逐一解釋比較重要的部分。
『if kindex(text,"中山路")>=1 then do』,利用「kindex」找出字串包含有中山路的第一個位置(注意是字串非單獨的字),以第1筆地址來看,kindex回應4,如果是第2筆地址則回應為0。所以當kindex回應等於或大於1時表示該地址中有「中山路」字串的存在,我們在進一步的處理。
『text1=kcompress(KUPDATE(text,kindex(text,"中山路"),3,""))』,這一串函數中最重要的就是「kupdate」了,使用這個函數將字串中的特定「範圍」的字或字串取代成其他的,而要取代的起點則透過『kindex(text,"中山路")』設定,要取代的長度則設定為「3」。
『else text1=text』,將沒有包含「中山路」的地址直接使用原本的地址。不過要直接取代成原來變項的話,則可以跳過這一段語法。
結果如下圖:
當然我們不能只滿足這樣的語法,希望能把Macro的精神放到程式裡面,讓大家可以更偷懶!!
我們先來看看程式可改進的地方,最主要的問題就是需要自訂長度,如果能把自訂長度「3」改為自動抓取需要取代字串長度,且不用寫那麼多if then else可能會更棒。
所以把程式稍做修改成下面的macro語法了。
%macro textchange (var, ctext);
%let clength=%sysfunc(KLENGTH(&ctext));
%put &clength;
if kindex(&var,"&ctext")>=1 then do;
&var=kcompress(KUPDATE(&var,kindex(&var,"&ctext"),&clength,""));
end;
%mend textchange;
以上的macro程式主要新增自動抓取文字長度的語法,『%let clength=%sysfunc(KLENGTH(&ctext))』,「%sysfunc」讓macro語法可以使用SAS內建函數的巨集函數。「klength」為k函數用來找出字串的長度。
實際使用的程式和結果
data c;
set a;
%textchange(text, 中山路);
%textchange(text, 中正北路);
%textchange(text, 建國路);
run;
proc print data=c;
run;
以上的部分主要解決將特定字串刪除的的問題。
在來我將這個問題轉換一下,處理地址的時候,常遇到六都的「鄉鎮市」轉換為區,寫了一段稍微複雜的程式給大家參考,不過這組程式沒有很精簡,但我也懶得修改了,也請容許我不說明這個程式的細節了。
Macro程式(使用兩組程式,個人不喜歡把程式包來包去)
%macro subprog ( subleng);
&var=KSTRCAT( ksubstr(&var,1,kindex(&var,"&old_text")+2),
KTRANSLATE(ksubstr(&var,kindex(&var,"&old_text")+3,&subleng),"區區區","鄉鎮市"),
ksubstr(&var,kindex(&var,"&old_text")+3+&subleng)) ;
&var=kcompress(KUPDATE(&var,kindex(&var,"&old_text"),&clength,"&new_text"));
%mend subprog;
%macro textchange (var, old_text, new_text);
%let clength=%sysfunc(KLENGTH(&old_text));
%put &clength;
if kindex(&var,"&old_text")>=1 then do;
if ksubstr(&var,kindex(&var,"&old_text")+3,3) not in ("那瑪夏") then do;
%subprog (3);
end;
else do;
%subprog (4);
end;
end;
%mend textchange;
程式使用說明:
『%textchange (要取代的變項, 被取代的字串, 新字串);』
範例:
%textchange(text, 台北縣, 新北市);
建立練習資料檔
data a1;
format text $100.;
input text $;
cards;
24104台北縣三重市重新路4段12號6樓
33049桃園縣桃園市三元街156號
33001桃園縣桃園市市府路1號
22055臺北縣板橋市文化路一段48號
849高雄縣那瑪夏鄉達卡努瓦里大光巷230號
台中市北區學士路91號
台中縣大甲鎮鎮政路40號
;
實際應用
data a2;
set a1;
%textchange(text, 台北縣, 新北市);
%textchange(text, 臺北縣, 新北市);
%textchange(text, 桃園縣, 桃園市);
%textchange(text, 台中縣, 臺中市);
%textchange(text, 高雄縣, 高雄市);
run;
proc print data=a2;
run;
結果
沒有留言:
張貼留言