压缩动态变量的换行符
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;
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;