2015年8月21日金曜日

SCAN関数の落とし穴




私自身がSCAN関数にはめられた出来事を紹介。
SCAN関数とは、、、まず例をご覧ください。




data DT0;
   length A  A1-A3  $10.;
   A="aa,bb,cc";

   A1 = scan( A, 1, "," );
   A2 = scan( A, 2, "," );
   A3 = scan( A, 3, "," );
run;

 A  
 A1  
 A2  
 A3  
 aa,bb,cc 
 aa
 bb
 cc

上の例では、「aa,bb,cc」という文字列をカンマ「,」で区切って分割しています。
つまり、文字列を、指定した1文字で区切った時のn個目の文字を返してくれるのがSCAN関数です。

勘違いしやすいのが、例えば区切る文字に「,:」と指定したら「,」と「:」の2つが区切り文字になります。
「,:」というひとつづきの文字が区切り文字になるという意味ではないです。



構文

 SCAN( 文字列または変数 , n個目 , "区切り文字" )

  • 日本語などのマルチバイト文字には対応していません。マルチバイト文字を扱う場合は、KSCAN関数というのが用意されています。




落とし穴

以下のプログラムの結果は想定通りでしょうか?

* テストデータ ;
data DT1;
input A :$10.;
cards;
aa,bb
aa
,aa
aa,,bb
;

* SCAN関数で分割 ;
data OUT1;
   set DT1;
   length A1-A3 $5.;

   A1 = scan(A, 1, ",");
   A2 = scan(A, 2, ",");
   A3 = scan(A, 3, ",");
run;

 A  
 A1  
 A2  
 A3  
 aa,bb 
 aa
 bb

 aa 
 aa

 ,aa 
 aa

 aa,,bb 
 aa
 bb


以下の結果を想定した方も多いと思います。
 A  
 A1  
 A2  
 A3  
 aa,bb 
 aa
 bb

 aa 
 aa

 ,aa 
 aa

 aa,,bb 
 aa
 bb


この現象は以下のルールによるものです。

  • 3行目の「,aa」のように一番先頭に区切り文字があると、先頭の区切り文字は無視される。
  • 4行目の「aa,,bb」のように区切り文字が連続している場合、区切り文字は1つだけと解釈される。



このルールを無効にしたい場合、SCAN関数に”M修飾子”というものをつけてやります。

* SCAN関数で分割 ;
data OUT2;
   set DT1;
   length A1-A3 $5.;

   A1 = scan(A, 1, "," , "M");
   A2 = scan(A, 2, "," , "M");
   A3 = scan(A, 3, "," , "M");
run;

 A  
 A1  
 A2  
 A3  
 aa,bb 
 aa
 bb

 aa 
 aa

 ,aa 
 aa

 aa,,bb 
 aa
 bb


できた!
ただし、KSCAN関数には”M修飾子”の機能がありません。
(SAS9.4M5からKSCANX関数というのが追加されて同様の構文で"M修飾子"がつかえます)



0 件のコメント:

コメントを投稿