2018年11月20日火曜日

FORMATの落とし穴【デフォルト長】




以下のプログラムと結果をご覧ください。結果は想定通りでしょうか?

proc format;
   value $FMT
       "a"    = "x"
       "abc" = "y"
   ;
run;

data DT1;
   format VAR1 $FMT.;
   VAR1 = "abc";
run;

  VAR1  
  x 

変数VAR1は "abc" なのでフォーマット$FMTを貼りつけると "y" と表示されるはずが、 "x" が表示されてしまいました。



原因

これは「デフォルト長 (Default Length)」というものが関係してます。
例えば、今回の例で

proc format;
   value $FMT
       "a"    = "x"
       "abc" = "y"
   ;
run;


右側に定義した値 ("x" と "y") の文字の長さは1バイトです。
この長さが、そのフォーマットの「デフォルト長」というものになります。
(定義した値が複数ある場合は、右側の文字の長さが最も大きいものがそのフォーマットの「デフォルト長」になる)



そしてこのフォーマット$FMTは、以降のFORMATステートメントでデフォルト長となった1バイトしか視界に入らなくなります。
どういう事かというと、、

data DT1;
   format VAR1 $FMT.;
   VAR1 = "abc";
run;

変数VAR1 の値 "abc" から先頭の1バイトの値 "a" だけを見て対応するフォーマット値を表示しようとします。



ちょうど PROC FORMAT で "a" = "x" と定義してたので、この値が表示されちゃったというわけですね。

proc format;
   value $FMT
       "a"    = "x"
       "abc" = "y"
   ;
run;


解決策

変数VAR1 の値 "abc" の文字の長さは3バイトなので、3バイト全部読み込んで表示する必要があります。
解決策としては以下の2つの方法があります。


解決策①
proc format;
   value $FMT (default=10)
       "a"    = "x"
       "abc" = "y"
   ;
run;

data DT1;
   format VAR1 $FMT.;
   VAR1 = "abc";
run;

  VAR1  
  y 

「DEFAULT=オプション」によってこのフォーマットのデフォルト長を 10 に広げています。


解決策②
proc format;
   value $FMT
       "a"    = "x"
       "abc" = "y"
   ;
run;

data DT1;
   format VAR1 $FMT10.;
   VAR1 = "abc";
run;

  VAR1  
  y 

FORMATステートメントで、フォーマット名の後ろに幅を指定することも出来ます。




See also

インフォーマットでも同様の落とし穴があります。
INFORMATの落とし穴【デフォルト長】


ポイント
・文字値から数値に変換するインフォーマットの場合、「左側」に定義した文字の長さがデフォルト長になる。
・フォーマットの場合、「右側」に定義した文字の長さがデフォルト長になる。


0 件のコメント:

コメントを投稿