Macros 在SAS宏变量中分隔字

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

假设我有一个宏变量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 */  ) ;
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;