2016年5月19日木曜日

マクロ言語入門5:クォート処理【%STR関数】





クォート処理とは?



以下は、変数Aに値を入れるマクロです。

%macro TEST( VAL );

       data DT1;
           length A $30.;
           A = "&VAL";
       run;

%mend;


このマクロを実行して変数Aに「A,B,C」という値を入れたいとします。

 
 A,B,C  


何も考えず書くと、、

%TEST(A,B,C);

ログ
ERROR: マクロに定義された数よりも多い定位置パラメータが与えられています。

エラーが出ます。これは%TEST(A,B,C)にカンマが含まれてるので「3つ引数があるのか」と解釈されてしまうからです。



解決策
%STR関数で囲ってあげます。

%TEST( %str(A,B,C) );

 
 A,B,C  


%STR関数は、カンマやセミコロンなどSASの構文として意味のある特定の文字を、ただの文字として解釈させる関数です。
このただの文字として解釈させる事を「クォート処理」といいます。





%STR, %NRSTR関数



関数によってクォート対象の文字が異なります。

マクロ関数対象の文字備考
%STR




+ - * / < > = ¬ ^ ~ ; , # 半角スペース
AND OR NOT EQ NE LE LT GE GT IN



' " ( )
上記文字をクォートしたい場合、その文字の前に%をつける(%直後の1文字のみに効果がある)
この方法の落とし穴を記事の下の方の例③に示しているので要確認!
%NRSTR

%STR関数と同じ+ & %

%STR関数と同じ



ちなみに%NRSTR の先頭の「NR」は 「Not Resolved」の意味で、つまり「マクロやマクロ変数を展開させない」という意味合いがあります。
なので&や%がクォート対象となっています。



では最初に書いたマクロTESTを使って、クォート処理の例を紹介します。
(例③④は落とし穴的な挙動なので要注意です!)






例①
欲しい結果
 
 Mr.&Mrs.Smith  

「&Mrs」 というマクロ変数として解釈されないようクォート処理をします。
%TEST( %nrstr(Mr.&Mrs.Smith);




例②
欲しい結果
 
 It's a small world  

シングルクォーテーションをクォート処理します。
%TEST( %str(It%'s a small world);



例③
欲しい結果
 
 100%JUICE  

「%JUICE」 というマクロとして解釈されないようクォート処理をします。
%TEST( %nrstr(100%JUICE);
   または
%TEST( %nrstr(100%%)JUICE );

2個目の例を「%TEST( %nrstr(100%)JUICE )」とすると、、

%NRSTR関数での「%)」は「)」をクォート処理せよという命令になってしまいます(%NRSTR関数の閉じカッコがクォート処理されるのでSASの挙動もおかしくなる)

そこで%STR, %NRSTR関数内に「%%」と書くと、
  • この「%」は直後の文字「'」「"」「(」「)」をクォートするという意味ではない、と命令する
  • 「%%」は「%」に置き換わる



例④
欲しい結果
 
 /* abcd */  

コメントステートメントとして解釈されないようクォート処理をします。
%TEST( %str(/)%str(*) abcd %str(*)%str(/) );

「%TEST( %str(/* abcd */) )」という書き方はNG。%STR関数の中でもコメントステートメントとして認識されるからです。なので「/*」を1文字ずつ%STR関数で分けてクォート処理しています。

ちなみに、コメントステートメントの種類(「/* */」「* ;」「%* ;」)によってマクロ内での挙動が異なっているのが影響してますが、
ほしい結果が「* abcd ;」の場合は「%TEST( * abcd ; )」という書き方でOK。
ややこしい。。コメントステートメントを含む文字をクォート処理する場合は挙動確認したほうが良いです。




(おまけ) シングルクォートとダブルクォート


以下プログラムは、&Mrsというマクロ変数が指定されてると解釈されてしまい、ログにWARNINGが出ます。

data OUT1;
  A = "Mr.&Mrs.Smith";
run;

ログ
WARNING: MRSのシンボリック参照を解決できません。


しかし、以下はWARNINGが出ず期待通りの結果が得られます。

data OUT2;
  A = 'Mr.&Mrs.Smith';
run;


これは「シングルクォーテーションで囲まれた文字に&や%が含まれていても、ただの文字として解釈される」というルールがあるからです。

0 件のコメント:

コメントを投稿