Sas 宏似乎卡在无限循环中,don';我不知道如何调试
我试图定义一个宏函数,它从一个空格分隔的列表中返回唯一的列表项。这个宏本身使用了我测试过的其他宏,它们自己似乎工作得很好(参见下面的示例),它们都是非常简单的代码 然而,由于某些原因,代码无限期地运行,我不知道如何正确地调试它。我通常使用Sas 宏似乎卡在无限循环中,don';我不知道如何调试,sas,sas-macro,Sas,Sas Macro,我试图定义一个宏函数,它从一个空格分隔的列表中返回唯一的列表项。这个宏本身使用了我测试过的其他宏,它们自己似乎工作得很好(参见下面的示例),它们都是非常简单的代码 然而,由于某些原因,代码无限期地运行,我不知道如何正确地调试它。我通常使用%put语句进行调试,但它们不会在这里打印,因为没有错误,我手动停止代码 这里是主宏,后面是我使用的其他方便宏,您可以执行整个批来加载宏,然后查看给定的示例 *---------------------------------------------------
%put
语句进行调试,但它们不会在这里打印,因为没有错误,我手动停止代码
这里是主宏,后面是我使用的其他方便宏,您可以执行整个批来加载宏,然后查看给定的示例
*---------------------------------------------------------------;
* LIST_UNIQUE ;
* Return only unique items from list, ;
* in order of first appearance ;
*---------------------------------------------------------------;
/* EXAMPLE
%put %list_unique(); ** (nothing)
%put %list_unique(a); ** a
%put %list_unique(a a); ** doesn't work (should be a)
%put %list_unique(a b); ** doesn't work (should be a b)
*/
%macro list_unique(data);
%local out curr_item;
%do i=1 %to %list_length(&data);
%let curr_item = %extract(&data,&i);
%if not %list_in(&curr_item,&out) %then %let out = &out &curr_item;
%end;
&out
%mend;
*---------------------------------------------------------------;
* LIST_LENGTH ;
* Length of space separated list ;
*---------------------------------------------------------------;
/* EXAMPLES :
%put %list_length(); ** 0
%put %list_length(item1 item2 item3); ** 3
*/
%macro list_length(data);
%sysfunc(countw(&data,%str( )))
%mend;
*---------------------------------------------------------------;
* LIST_IN ;
* check if item is in list ;
*---------------------------------------------------------------;
/* EXAMPLE
%put %list_in(,a); ** 0
%put %list_in(a,); ** 0
%put %list_in(a,a); ** 1
%put %list_in(a,a a); ** 1
%put %list_in(b,a b c d); ** 1
%put %list_in(e,a b c d); ** 0
*/
%macro list_in
(item /* item to search in list */
,list /* space separated list to quote */
);
/* exception when list has null length */
%if not %length(&list) %then 0%return;
/* general case */
%do i=1 %to %list_length(&list);
%if %extract_pos(&list,&i) = &item %then 1%return;
%end;
0
%mend;
*-------------------------------------------------------------------------------;
* EXTRACT_POS ;
* Extracts subset of values from space separated list ;
*-------------------------------------------------------------------------------;
/* EXAMPLES
%put %extract_pos(,1); ** (nothing)
%put %extract_pos(a b c d,); ** (nothing)
%put %extract_pos(a b c d,1); ** a
%put %extract_pos(a b c d,2 1:3 1); ** b a b c a
*/
%macro extract_pos
(data
,ind
);
%local i j token output new_ind;
%do i=1 %to %sysfunc(countw(&ind,%str( )));
%let token = %scan(&ind,&i,%str( ));
%if %index(&token,:) %then %do; /* if token with ':' */
%do j=%scan(&token,1,:) %to %scan(&token,2,:);
%let output = &output %scan(&data,&j,%str( ));
%end;
%end;
%else %do; /* if simple token */
%let output = &output %scan(&data,&token,%str( ));
%end;
%end;
&output
%mend;
Options macrogen symbolgen mlogic mprint mfile;
Options nomacrogen NoSymbolgen nomlogic nomprint nomfile;
变量
I
在命名空间中向下共享。一个简单的解决方法是在每个宏中使用不同的循环变量
找到一些关于共享SAS逻辑的文档 您无法保护您调用的宏不被修改宏变量,但是如果宏设计正确,它们就不会被修改。除非您打算修改任何现有的宏变量,否则您需要将宏变量定义为本地变量。一个或多个宏正在使用宏变量
I
,但未将其定义为本地变量。因此,如果已经存在名为I
的宏变量,则宏会修改现有变量的值
还有一个宏正在调用%extract()
,而不是%extract\u pos()
我还将%list\u in()
宏简化为对现有SAS函数的调用,就像您的%list\u length()
宏一样
%macro list_unique
/*---------------------------------------------------------------
Return only unique items from list
---------------------------------------------------------------*/
(data /* Space delimited list of items */
);
%local i curr_item out ;
%do i=1 %to %list_length(&data);
%let curr_item = %extract_pos(&data,&i);
%if not %list_in(&curr_item,&out) %then %let out=&out &curr_item;
%end;
&out
%mend list_unique;
%macro list_length(data);
%sysfunc(countw(&data,%str( )))
%mend list_length;
%macro list_in
/*---------------------------------------------------------------
Check if item is in list
---------------------------------------------------------------*/
(item /* item to find in list */
,list /* space separated list to search */
);
%sysevalf(%sysfunc(indexw(&list,&item,%str( ))),boolean)
%mend list_in;
%macro extract_pos
/*-------------------------------------------------------------------------------
Extracts subset of values from space separated list
-------------------------------------------------------------------------------*/
(data /* Space delimited list of values */
,ind /* Space delimited list of positions or position ranges */
);
%local i j token output;
%do i=1 %to %sysfunc(countw(&ind,%str( )));
%let token = %scan(&ind,&i,%str( ));
%do j=%scan(&token,1,:) %to %scan(&token,-1,:);
/* Token is single position or range in format start:end */
%let output = &output %scan(&data,&j,%str( ));
%end;
%end;
&output
%mend extract_pos;
试验
可能变量
I
在extract\u pos
宏中的list\u之间共享?我会尝试使用特定于宏的循环变量名。很好!问题是我天真地假设在%do
语句中创建的变量是本地变量,而不是本地变量。在所有宏中使用i
本地解决了这个问题(不需要不同的名称)。它似乎不太可靠,如何跟踪使用了哪些名称?尤其是当你和别人分享的时候。仅仅确保它们被设置为本地变量有什么错?我很愿意接受你的答案,因为你发现了问题,但我不喜欢你的额外建议:)@Moody\u mudscappper嗯,你可以看到%put\u user\uu
使用的所有变量,其中列出了所有正在使用的变量。我明白你的意思。应该有更可靠的方法。回答得好,汤姆。我也一直很欣赏关于格式化和如何改进我的便利功能的提示。更新以消除extract_pos中的%if
,并且只使用-1作为%do j
循环的上限。这样,当令牌为单值时,do循环仅覆盖一个值<代码>%do j=%scan(&token,1,:)%到%scan(&token,-1,:)代码>
831 %put %list_unique(); %** (nothing);
832 %put %list_unique(a); %** a ;
a
833 %put %list_unique(a a); %** doesnot work (should be a);
a
834 %put %list_unique(a b); %** doesnot work (should be a b);
a b