压缩动态变量的换行符

Compress Newline character for dynamic varaibles

Dataset: Have
F1      F2

Student Section
Name    No

数据集"Have"。数据有换行符。

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

我想动态地执行此操作,因为有时 "Have" 数据集可能包含新变量,例如 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.,

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

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

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

这是另一种选择。如果换行符是您唯一要删除的内容,那么我们只讨论 Char,您可以利用隐式数组并重做,

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

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

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

  function clean(iField $) 0;    
    length cleaned 0;
    bad_char_list = byte(10) || byte(9) || byte(13);  
    cleaned = translate(iField," ",bad_char_list);
    return (cleaned );
  endsub;

run;

创建一些中间有换行符的测试数据,然后导出并查看结果。您可以看到字符串已被拆分为多行:

data x;
  length employer 0;
  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;

EDIT :另请注意,fcmp 可能需要考虑一些性能因素。如果您要处理大量数据,可能还有其他性能更好的解决方案。

编辑 6/15/2020:更正了可能导致响应被截断的缺失长度语句。

这里有一个 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 ;
  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;