【问题标题】:Delimiting words in a SAS macro variable在 SAS 宏变量中分隔单词
【发布时间】:2014-04-18 01:06:38
【问题描述】:

假设我有一个宏变量 x,它可以包含任意数量的纯字母单词,每个单词由一个或多个空格分隔:

%let x =   A B      CD   ;

我想创建另一个宏变量,在打印时会给出这个结果(单引号也可以换成双引号):

'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;

但我无法摆脱那个该死的音符。

【问题讨论】:

  • 为什么要用宏语言做这个?这对我来说听起来像是数据操作。
  • 答案已更新以解决您的问题。 &x 中的值作为参数传递给 SAS。
  • 难道您不能使用indexw 而不是in 作为您的if 条件并获得相同的结果而不必担心插入大量引号吗?请参阅下面的答案。
  • @user667489 是的-鉴于我的原始示例代码,您是对的。这是一个不好的例子,因为我实际上应该在where 语句中使用它来利用索引。我现在已经修改了。不过感谢您的建议。

标签: macros sas delimiter


【解决方案1】:

对于使用 CATS() 的 FCMP 尝试,您需要为结果变量添加 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'

【讨论】:

  • 非常感谢 - 看起来我应该去阅读 FCMP 的文档而不是盲目地使用它 =P
【解决方案2】:

如果您将 if 条件更改为使用 indexw 而不是 in 那么我认为您可以完全避免这个问题:

data want;
  set have;
  if indexw("&X",my_field) then do; 
    output;
  end;
run;

【讨论】:

  • 感谢您的建议。不过,请查看我针对原始问题更新的 cmets。
【解决方案3】:

知道了。诀窍是在添加引号时,通过插入空格来确保它们不与单词边界相邻。所以最初的字符串是用额外的空格填充的。然后在最后,我用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 会给我带来意想不到的结果,所以我只使用了 ||。可以通过允许用户指定构成单词边界的符号以及是否引用输出以及是否使用单引号或双引号来改进该功能......但我会根据需要添加它们。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-16
    • 2014-12-02
    相关资源
    最近更新 更多