Macros 在SAS宏变量中分隔字
假设我有一个宏变量x,它可以包含任意数量的纯alpha单词,每个单词之间用一个或多个空格分隔:Macros 在SAS宏变量中分隔字,macros,sas,delimiter,Macros,Sas,Delimiter,假设我有一个宏变量x,它可以包含任意数量的纯alpha单词,每个单词之间用一个或多个空格分隔: %let x = A B CD ; 我想创建另一个宏变量,在打印时给出这个结果(单引号也可以被双引号替换): 它用于in()语句中。。。例如,我想编写如下代码: data want; set have; where my_field in ( /* DO SOMETHING TO &X HERE TO GIVE DESIRED OUTPUT */ ) ; ru
%let x = A B CD ;
我想创建另一个宏变量,在打印时给出这个结果(单引号也可以被双引号替换):
它用于in()
语句中。。。例如,我想编写如下代码:
data want;
set have;
where my_field in ( /* DO SOMETHING TO &X HERE TO GIVE DESIRED OUTPUT */ ) ;
run;
我正在寻找一个(最好是一行)纯宏代码解决方案。未生成此便笺的便笺:
NOTE 49-169: The meaning of an identifier after a quoted string might change in a
future SAS release. Inserting white space between a quoted string and the succeeding
identifier is recommended.
到目前为止,我有:
%let y = %str(%')%sysfunc(tranwrd( %sysfunc(compbl(&x)) ,%str( ),%str(%',%') ))%str(%');
%put &y;
但我无法摆脱那张该死的纸条。明白了。诀窍是在添加引号时,通过插入空格确保引号不与单词边界相邻。因此,最初字符串中填充了额外的空格。然后在末尾,我用
compress()
删除了额外的空格。这样我们就可以偷偷地通过引用字符串标识符的测试
%let x = A B C ;
%let y = %sysfunc(compress(%str(%' )%sysfunc(tranwrd(%sysfunc(compbl(&x)), %str( ), %str( %',%' ) ))%str( %') ));
%put &y;
结果:
'A','B','C'
不过有点难看
编辑:第二次尝试:
我以为我会作弊并使用proc fcmp
。最终结果要好得多:
proc fcmp outlib=common.funcs.funcs;
function delimit_words(iString $) $;
result = "'" || tranwrd(cats(compbl(iString))," ", "','") || "'";
return (result );
endsub;
run;
数据步骤示例:
data x;
x = " A B C ";
y = delimit_words(x);
put y=;
run;
改进的宏示例:
%let x = A B C ;
%let y = %sysfunc(delimit_words(&x));
%put &y;
由于某种原因,如果我尝试使用cats()
函数而不是|
串联器,那么proc fcmp
会给我带来意想不到的结果,所以我选择了|
。该功能可以通过允许用户指定哪些符号构成单词边界,以及是否引用输出,如果是,是否使用单引号或双引号来改进。。。但是,我会根据需要添加它们。对于FCMP try with CATS(),需要为结果变量添加一个LENGTH
语句。FCMP处理字符变量的方式与数据步骤略有不同
proc fcmp outlib=work.funcs.funcs;
function delimit_words(iString $) $;
length result $200;
result = cats("'",tranwrd(cats(compbl(iString))," ", "','"),"'");
return (result );
endsub;
run;
options cmplib=work.funcs;
data _null_;
x = " A B C ";
y = delimit_words(x);
put y=;
run;
返回:
5136 data _null_;
5137 x = " A B C ";
5138 y = delimit_words(x);
5139 put y=;
5140 run;
y='A','B','C'
如果您将If条件更改为使用indexw而不是in,那么我认为您可以完全避免此问题:
data want;
set have;
if indexw("&X",my_field) then do;
output;
end;
run;
为什么要用宏语言来做这件事?对我来说,这听起来像是数据操纵。更新答案以解决您的问题。
&x
中的值作为一个参数传递到SAS中。您不能使用indexw
而不是中的来处理if条件,并获得相同的结果,而不必担心插入大量引号吗?请参阅下面我的答案。@user667489是-根据我最初的示例代码,您是对的。这是一个糟糕的例子,因为我实际上应该在where
语句中使用它来利用索引。我现在已经修改过了。谢谢你的建议。非常感谢-看起来我应该找个时间去阅读FCMP的文档,而不是盲目地使用它=p感谢你的建议。尽管如此,请参见我对原始问题的最新评论。
data want;
set have;
if indexw("&X",my_field) then do;
output;
end;
run;