首页 > 解决方案 > %SYSFUNC() 包装的连接函数在遇到括号时会出错

问题描述

我需要编写一个宏程序来生成一个用于移动平均计算的列表,我需要像这样构造一些行:

var1_ma_past_1=mean(var1, lag1(var1), lag2(var1), lag3(var1), lag4(var1), lag5(var1));
var1_ma_past_2=mean(lag1(var1), lag2(var1), lag3(var1), lag4(var1), lag5(var1), lag6(var1));
var1_ma_past_3=mean(lag2(var1), lag3(var1), lag4(var1), lag5(var1), lag6(var1), lag7(var1));
[...]
var2_ma_past_1=mean(var2, lag1(var2), lag2(var2), lag3(var2), lag4(var2), lag5(var2));

我的示例程序是

%macro test ;
    %do i = 1 %to 5;
    %let ln&i = ;
        %do j = 1 %to 5;
            %let dml = %str(,);
            %let pos = %str(lag&i(var&j));
            %let ln&j = %sysfunc(catx(&dml, &&ln&j, &pos));
        %end;
    %end;
    /* example output */
    %put &ln1;
%mend test;
%test

&j不过,开始和结束值计划用参数替换。

输出是需要的&ln1

lag1(var1),lag2(var1),lag3(var1),lag4(var1),lag5(var1)

但对于&ln2 &ln3等它不是(lag1(varn)缺失)

lag2(var4),lag3(var4),lag4(var4),lag5(var4)
lag2(var3),lag3(var3),lag4(var3),lag5(var3)

此外,我得到了泛滥的日志输出,说ERROR: Required operator not found in expression:这是因为里面的括号cats(),这是里面的%sysfunc(),复制这个的示例宏是

%macro test2;
    %let x=meow;
    %put %sysfunc(cats(x,lag()));
%mend;
%test2

我试图用 , 掩盖括号,%str但没有奏效。%superq%bquote

我想学习

  1. 的输出不正确的原因&ln2&ln3等等
  2. 修复它的原因ERROR: Required operator not found in expression:以及如何修复它(或解决方法,或者如果它不重要,甚至可以抑制错误)

提前致谢。

标签: functionloopsmacrossas

解决方案


无需在宏代码中使用 CAT...() 函数。

在用于连接值的宏代码中,您只需将它们彼此相邻展开。此外,您的逻辑似乎混淆了 I 和 J 计数器。

%macro test ;
%do i = 1 %to 5;
  %let list = ;
  %let dlm = ;
  %do j = 1 %to 5;
    %let list = &list.&dlm.lag&j(var&i) ;
    %let dlm = ,;
  %end;
  %put &=i &=list;
%end;
%mend test;
%test

结果:

I=1 LIST=lag1(var1),lag2(var1),lag3(var1),lag4(var1),lag5(var1)
I=2 LIST=lag1(var2),lag2(var2),lag3(var2),lag4(var2),lag5(var2)
I=3 LIST=lag1(var3),lag2(var3),lag3(var3),lag4(var3),lag5(var3)
I=4 LIST=lag1(var4),lag2(var4),lag3(var4),lag4(var4),lag5(var4)
I=5 LIST=lag1(var5),lag2(var5),lag3(var5),lag4(var5),lag5(var5)

对于您的实际问题,您可能希望创建一个仅返回逗号分隔列表作为宏调用结果的宏。

%macro lags(varname,first,last);
%local lag dlm;
%do lag= &first %to &last ;
  %if (&lag > 0) %then %*;&dlm.lag&lag(&varname);
  %else %*;&dlm.&varname;
  %let dlm=,;
%end;
%mend lags;

%put var1_ma_past_1=mean(%lags(var1,0,5));
%put var1_ma_past_2=mean(%lags(var1,1,6));
%put var1_ma_past_3=mean(%lags(var1,2,7));
%put var2_ma_past_1=mean(%lags(var2,0,5));

为什么您会收到这些错误消息:

%sysfunc()宏函数需要尝试确定每个参数是字符还是数字,因为这样的函数可以CATX()对任何一种类型的输入进行操作。这就是为什么()in 参数值会混淆它,因为看起来您正在尝试传递数字表达式。

18    %put %sysfunc(catx(|,a(b),b));
ERROR: Required operator not found in expression: a(b)
a(b)|B
19    %put %sysfunc(catx(|,(1+2),b));
3|B

您可以强制在值周围加上引号,然后稍后将其删除(如果您的值实际上不包含引号)。

%let left=A(b);
%let right=b;
%let intermediate=%sysfunc(catx(|,"&left","&right"));
%let want=%sysfunc(compress(&intermediate,%str(%"));
%put &=want;

推荐阅读