为什么 `%str(%inner_macro())` 中的 %str 不起作用?

Dir*_*ten 4 sas sas-macro

%str 应该将一个字符串作为一个参数传递给 sas 宏,即使它包含逗号,但如果 %str 的参数本身就是宏的结果,那么这显然不起作用?我明白了ERROR: More positional parameters found than defined.

例子

这就是错误的含义

    15         %macro outer_macro(left, right);
    16          %put NOTE: outer_macro: left is &left;
    17          %put NOTE: outer_macro: right is &right;
    18         %mend;
    19         %outer_macro(left, right);
    NOTE: outer_macro: left is left
    NOTE: outer_macro: right is right
    20         %outer_macro(left, midle, right);
    ERROR: More positional parameters found than defined.
Run Code Online (Sandbox Code Playgroud)

%str正常情况下是这样解决的。

    21         %outer_macro(left, %str(midle, right));
    NOTE: outer_macro: left is left
    NOTE: outer_macro: right is midle, right
Run Code Online (Sandbox Code Playgroud)

可以用内部宏构造宏的参数

    23         %macro blank_macro(left, right);
    24          %put NOTE: blank_macro: left is &left;
    25          %put NOTE: blank_macro: right is &right;
    26          &left. &right.
    27         %mend;
    28         %outer_macro(links, %blank_macro(midden, rechts));
    NOTE: blank_macro: left is midden
    NOTE: blank_macro: right is rechts
    NOTE: outer_macro: left is links
    NOTE: outer_macro: right is midden rechts
Run Code Online (Sandbox Code Playgroud)

但是如果内部宏插入逗号,您会得到原始错误

    30         %macro comma_macro(left, right);
    31          %put NOTE: comma_macro: left is &left;
    32          %put NOTE: comma_macro: right is &right;
    33          &left., &right.
    34         %mend;
    35         %outer_macro(left, %comma_macro(midle, right));
    NOTE: comma_macro: left is midle
    NOTE: comma_macro: right is right
    ERROR: More positional parameters found than defined.
Run Code Online (Sandbox Code Playgroud)

我希望%str能够解决这个问题,但事实并非如此。为什么?

    36         %outer_macro(left, %str(%comma_macro(midle, right)));
    NOTE: comma_macro: left is midle, right
    NOTE: comma_macro: right is
    ERROR: More positional parameters found than defined.
Run Code Online (Sandbox Code Playgroud)

语境

供您参考:我需要这个,因为我编写了一个宏来列出我应该从数据库查询的一些字段,并且我需要通过另一个宏将我的 sql 传递到数据库。

%run_SQL(select key, %list_fields(some_arguments), from something);
Run Code Online (Sandbox Code Playgroud)

Joe*_*Joe 5

您遇到的问题是在宏编译期间而不是在宏执行%str期间屏蔽字符。因此,宏调用会正确编译、执行,但是一旦执行,这些值就不再被引用(因为已经完成了它的工作)。它不会再次掩盖这些%comma_macro%str

%comma_macro您的电话也是错误的这一事实进一步证明了这一点。它掩盖了,,然后导致%comma_macro认为midle,right是第一个参数(与您在%str宏括号内使用的情况相同)。

请注意,SAS 在%str 文档中特别提到这种做法是危险的:

不要使用 %STR 来括起具有参数值列表的其他宏函数或宏调用。 由于 %STR 屏蔽了不匹配的括号,因此宏处理器无法识别函数的参数或宏调用的参数值。

%quote与 相同%str,只是它在解析期间屏蔽字符

%QUOTE 和 %NRQUOTE 分别屏蔽与 %STR 和 %NRSTR 相同的项目。但是,%STR 和 %NRSTR 屏蔽常量文本而不是解析值。并且,%STR 和 %NRSTR 在宏编译时起作用,而 %QUOTE 和 %NRQUOTE 在宏执行时起作用。

在您的示例中,替换%str%quote效果非常好。然而,我认为%bquote这可能是首选,因为它为不匹配的引号提供了额外的保护。我一直认为bin%bquote代表better,并且从未见过使用它的理由%quote

%BQUOTE 和 %NRBQUOTE 函数在执行宏或宏语言语句期间屏蔽字符串或文本表达式的解析值。

这听起来就像你对我做的事。您不需要使用%NRBQUOTE,除非& %结果中可能包含字符。

宏引用时间线表:

Quoting Type  | Occurs At       | Mask details
%str          | Compilation     | Unmatched Quotations/Parens with %
%nrstr        | Compilation     | Same as %str plus & %
%quote        | Execution       | Same as %str
%nrquote      | Execution       | Same as %quote plus & %
%bquote       | Execution       | Unmatched quotes/parens automatically
%nrbquote     | Execution       | Same as %bquote plus & %
%superq       | Execution       | Only variable and without &, same list as %nbrquote
 (continuned)                   | Does not attempt to resolve anything inside of variable
Run Code Online (Sandbox Code Playgroud)