压缩动态变量的换行符

时间:2015-07-24 06:55:04

标签: sas sas-macro

Dataset: Have
F1      F2

Student Section
Name    No

数据集"有"。数据有新的线条特征。

我需要从数据中压缩换行符。

我想动态地这样做,因为有时"有"数据集可能包含新变量,如F3,F4,F5 etc.

我已经写了宏来做这个..但它没有按预期工作。

当我执行下面的代码时,第一次我收到错误作为无效的引用newcnt。如果我在同一个会话中第二次执行,我没有收到错误。

PFB我的代码:

%macro update_2(newcnt);

data HAVE;
    set HAVE;
    %do i= 1 %to &newcnt;
        %let colname = F&i;
        &colname=compress(&colname,,'c');
    %end;
run;

%mend update_2;


%macro update_1();

proc sql noprint;
    select count(*) into :cnt from dictionary.columns where libname="WORK" and memname="HAVE"; 
quit;

%update_2(&cnt)

%mend update_1;

注意:所有变量的名称都为F1,F2,F3,F4.

请告诉我出了什么问题..

如果还有其他程序,请帮助我。

4 个答案:

答案 0 :(得分:3)

在您的宏%update_1中,您创建了一个名为&cnt的宏变量,但是当您调用%update_2时,您会引用另一个宏变量&colcnt。尝试修复此引用,看看您的代码是否按预期运行。

答案 1 :(得分:2)

我们创建了自己的函数,使用proc fcmp从字符串中清除不需要的字符。在这种情况下,我们的函数会清除制表符,换行符和回车符。

proc fcmp outlib=common.funcs.funcs; /* REPLACE TARGET DESTINATION AS NECESSARY */

  function clean(iField $) $200;    
    bad_char_list = byte(10) || byte(9) || byte(13);  
    iCleaned = translate(iField," ",bad_char_list);
    return (iCleaned );
  endsub;

run;

使用中间的新行字符创建一些测试数据,然后将其导出并查看结果。您可以看到字符串已跨行分割:

data x;
  length employer $200;
  employer = cats("blah",byte(10),"diblah"); 
run;

proc export data=x outfile="%sysfunc(pathname(work))\x.csv" dbms=csv replace;
run;

对字符串运行新创建的clean()函数并再次导出。您可以根据需要看到它现在在一行上:

data y;
  set x;
  employer = clean(employer);
run;

proc export data=y outfile="%sysfunc(pathname(work))\y.csv" dbms=csv replace;
run;

现在将此方法应用于我们所需数据集中的所有字符变量。不需要宏,只需定义一个引用所有字符变量的数组,然后在应用clean()函数时迭代它们:

data cleaned;
  set x;
  array a[*] _char_;
  do cnt=lbound(a) to hbound(a);
    a[cnt] = clean(a[cnt]);
  end;
run;

编辑:另请注意,fcmp可能需要考虑一些性能问题。如果您正在处理大量数据,可能会有其他解决方案表现更好。

答案 2 :(得分:2)

以下是Robert Penridge函数的示例,作为以数组作为参数的调用例程。这可能仅适用于9.4+或更高版本的9.3,当永久数组开始被允许以这种方式用作参数时。

我不确定这是否可以通过数组作为函数灵活地完成;不使用宏(需要不断重新编译函数)我不知道如何在不将其作为调用例程的情况下返回正确的数组大小。

我在下拉列表中添加了“Z”,因此很明显它可以正常工作。

options cmplib=work.funcs;

proc fcmp outlib=work.funcs.funcs;
  sub clean(iField[*] $);  
    outargs iField; 
    bad_char_list = byte(11)|| byte(10) || byte(9) || byte(13)||"Z";  
    do _i = 1 to dim(iField);
      iField[_i] = translate(iField[_i],trimn(" "),bad_char_list);
    end;
  endsub;
quit;


data y;
  length employer1-employer5 $20;
  array employer[4] $; 
  do _i = 1 to dim(employer);
    employer[_i] = "Hello"||byte(32)||"Z"||"Goodbye";
  end;
  employer5 = "Hello"||byte(32)||"Z"||"Goodbye";
  call clean(employer);
run;

proc print data=y;
run;

答案 3 :(得分:1)

这是另一种选择。如果你想要删除换行符,那么我们只讨论Char,你可以利用隐式数组和Do over,

data want;
set have;
array chr _character_;
do over chr;
chr=compress(chr,,'c');
end;
run;