%superqとかのあんまり面白くないマクロのクォートの話

マクロ絡みの話です。
&とか%とか;とか、そういうSASにとって意味のある記号が、含まれる際に
そいつらをただの文字として扱いたい場合にマクロ引用符関数といったものを使います。
ほっとくと勝手に展開しようとしたり、変なとこで区切って解釈されてエラーになりますからね。
いわゆるクォート処理です。

(SASmemo - マクロ関数、自動マクロ変数一覧)
http://www50.atwiki.jp/sasmemox/pages/56.html

(Welcome to データ分析・マイニングの世界 by SAS)
http://wikiwiki.jp/cattail/?Base%20SAS%A5%DE%A5%AF%A5%ED

ただ、マクロのクォート周りはあんまり得意じゃなくて
正直きっちりと理解できてません。

なので、あんまり僕の説明はあてにしないでください。

さて、以下のようなデータがあるとします。
どうでもいい話ですが、世の中には結構「&」の入った会社名って多いんですよね
SASプログラマーにはつらい話です。

data Q1;
X='A&A';Y=1;Z=3;output;
X='B&B';Y=2;Z=2;output;
X='C&C';Y=3;Z=1;output;
run;

そこで、マクロ変数に値を入れて、それによって抽出を行うコードを考えてみましょう

%let MA = B&B ;

data E1;
 set Q1;
 where X = "&MA" ;
run;

まあ、できたデータセットE1の中をみると一応「B&B」で抽出できてるんですが
ログに
WARNING: 記号参照 B を展開していません。」というメッセージがでています。
これは%let MA = B&B ;の時点で「&B」の部分を「B」というマクロ変数と解釈して
それを展開しようとしたけどBというマクロ変数がなかったので展開できずに、B&Bという文字列のまま
マクロ変数MAに入れましたという意味です。

今回はBというマクロ変数がなかったので、WARNINGがうざいなってだけで済みますが、もし
あった場合は展開されて、本来予期しない結果になってしまいます。

それを防ぐにはまず。

%let MA = %nrstr(B&B);

data A1;

 set Q1;
 where X = "&MA" ;
run;

こういうアプローチがとれます。%nrstrで「&」をただの文字扱いにしています。


では、マクロ変数の生成が%letではなく、call symput(x)の場合はどうでしょうか?

例えば

data _null_;
call symputx('MA','B&B');
run;

data E2;

set Q1;
where X = "&MA" ;
run;

とすると先程と同じようにWARNINGがでます。


これもまあ、

data _null_;
call symputx('MA','%nrstr(B&B)');
run;

とすれば一応解決です。


ただ、これまで見てきたのはマクロ変数に値を格納する際にクォート関数で
包んで一緒に入れてやることで、展開時に文字とみなしてやろうぜという発想です。

次は、そうではなくて、マクロ変数定義は以下のようにクォート関数なしで
そのまま格納し

data _null_;
call symputx('MA','B&B');
run;

展開時になんとかして、文字として解釈させようぜという発想のコードです。

その場合、以下のように書けます。

data A2;
set Q1;
where X = "%superq(MA)" ;
run;

superq関数はとても説明しにくいので、人の言葉を借ります

引数に指定されたマクロ変数の値に対してマクロプロセッサが展開を行わないようにした上で、その値に含まれる特殊文字をクォート」(SASmemo)
引数に与える文字列をマクロ変数名とみなし、1回だけ展開した値を返す」(Welcome to データ分析・マイニングの世界 by SAS)
The %SUPERQ function locates the macro variable named in its argument and quotes the value of that macro variable without permitting any resolution to occur.(SAS(R) 9.2 Macro Language: Reference)


或いは以前、紹介したsymget関数も、この場合は使えます。こいつはマクロ変数を展開した文字値を返すSAS関数です。

SYMGET関数でマクロ変数の値を取得する
http://sas-tumesas.blogspot.jp/2013/12/symget.html

data A3;
set Q1;
where X = symget('MA') ;
run;

でOKです。

ただし、symget関数はあくまでただのSAS関数として値を返すものですので


例えば以下のようにマクロ変数に抽出式を入れて

data _null_;
call symputx('wh','Y=1&Z=3');
run;

展開する場合

data A4;
set Q1;
where %superq(wh);
run;

だと正しい結果になりますが


data E3;
set Q1;
where symget('wh') ;
run;

だと、3レコードとも抽出されます。
これは結構不思議かもしれませんが

symget('wh')の結果返される値がnullかどうかという真偽値によって
whereが働いてしまうからです。

つまりsymget('wh')が返すのはこの場合「Y=1&Z=3」という文字列なのですが
この文字列はnullじゃないですよね? よって全て真となって
意図した抽出にはならないわけです。

マクロのクォート周りは、ドツボにハマりやすいので、周りにマクロ組むのが上手い人が
いたら直ぐに聞いた方がいいですね!


2 件のコメント:

  1. Usually I do not read post on blogs, but I would like to say that this write-up very forced me to try and do it! Your writing style has been surprised me. Great work admin.Keep update more blog.
    R Language Training in Chennai

    返信削除
  2. It's really a nice experience to read your post. Thank you for sharing this useful information. If you are looking for more about R Programming institutes in Chennai | R Programming Training in Chennai

    返信削除