2023年12月1日金曜日

各種クオーテーションマークを含む文字列を持つマクロ変数を展開する話

 仕様を私がきちんと理解しているわけではないですが、クオーテーションマークを含んだ文字列を持つマクロ変数を展開するにはsymget関数を使うと便利ですよ、との紹介です。確かに展開は出来ているのですがどうしてこうなっているのかはわかっていないのであまり深く掘り下げないでください。

事の起こりは会社でよくできる後輩君から掲題のことを聞かれました。私のところでは紆余曲折あってマクロ変数を無事展開できたのですが、どうも後輩君のところではうまく展開できずにいました。手元ではできるのになんでだろうな…と思っていると、実際の展開箇所でsymget関数を使って展開するのと、マクロ変数を""で挟んで展開しているという違いに行きつきました。私はsymget関数を使っていましたが、正直この関数はcall symputxで作ったマクロ変数を同じdata stepで展開できる関数くらいにしか思っておらず、その他のマクロ変数の展開ではマクロ変数を""で挟むのもsymget関数を使うのも同じ挙動を示すと思っていました。ところが違うんですねえ…どうやら。

仮に以下のようなシングル、ダブルクオーテーションを両方含んだ文字列を持つマクロ変数hogeを準備して、データステップで展開するとします。

%let hoge = I'm a "sas" user' ;

このマクロ変数をダブルクオーテーションで挟んで展開すると、案の定errorが出ます。今の場合ではerrorが出るのでデータステップが完了していません。

  data aa ;

      hage = "&hoge" ;

NOTE: マクロ変数"HOGE"によって生成されたライン

1      "I'm a "sas" user ;'

       -----------

       49      388

               202

NOTE 49-169: 引用符で囲まれた文字列の後の識別子の意味は、将来のSASリリースで変わる可能性があります。

             引用符で囲まれた文字列と識別子の間にスペースを挿入することをお勧めします。

ERROR 388-185: 算術演算子を指定してください。

ERROR 202-322: オプションまたはパラメータを認識できません。無視します。

2238  run ;

NOTE: 以下の箇所で文字値を数値に変換しました。(行:カラム)

      1:2    1:13

NOTE: エラーが発生したため、このステップの処理を中止しました。

WARNING: データセットWORK.AAは未完成です。このステップは、0オブザベーション、2変数で停止しました。

WARNING: このステップを中止したため、データセットWORK.AAを置き換えていません。

NOTE: DATA ステートメント処理(合計処理時間):

      処理時間           0.03 秒

      CPU時間            0.03 秒


ところがマクロ変数hogeの展開をsymget関数で行うとerrorが出ず実行されます。

  data aa ;

      piyo = symget("hoge") ;

  /*    hage = "&hoge" ;*/

  run ;

NOTE: データセットWORK.AAは1オブザベーション、1変数です。

NOTE: DATA ステートメント処理(合計処理時間):

      処理時間           0.03 秒

      CPU時間            0.01 秒


出来上がったデータセットAAを見ると、不思議と格納されています。これなんでなんでしょうね。私は意識せずsymgetをなんでか使っていたので特に意識することなくここまで来てしまったのですが…