我有两个文本文件,一个包含没有标题的原始数据,另一个包含相关的列名和长度。我想使用这两个文件构建一个SAS数据集,其中包含来自一个文件的数据,其中列名和长度来自另一个。
包含数据的文件是固定宽度的文本文件。也就是说,每列数据都与文本文件的特定列对齐,并用空格填充以确保对齐。
datafile.txt:
John 45 Has two kids
Marge 37 Likes books
Sally 29 Is an astronaut
Bill 60 Drinks coffee
包含元数据的文件以制表符分隔,并带有两列:一列具有数据文件中列的名称,另一列具有该列的字符长度。名称按它们在数据文件中的显示顺序列出。
metadata.txt:
Name 7
Age 5
Comments 15
我的目标是拥有一个如下所示的SAS数据集:
Name | Age | Comments
-------+------+-----------------
John | 45 | Has two kids
Marge | 37 | Likes books
Sally | 29 | Is an astronaut
Bill | 60 | Drinks coffee
我希望每个列都是元数据文件中指定长度的字符。
必须有一种比我天真的方法更好的方法,即使用导入的元数据构造length
语句和input
语句,如下所示:
/* Import metadata */
data meta;
length colname $ 50 collen 8;
infile 'C:\metadata.txt' dsd dlm='09'x;
input colname $ collen;
run;
/* Construct LENGTH and INPUT statements */
data _null_;
length lenstmt inptstmt $ 1000;
retain lenstmt inptstmt '' colstart 1;
set meta end=eof;
call catx(' ', lenstmt, colname, '$', collen);
call catx(' ', inptstmt, cats('@', colstart), colname, '$ &');
colstart + collen;
if eof then do;
call symputx('lenstmt', lenstmt);
call symputx('inptstmt', inptstmt);
end;
run;
/* Import data file */
data datafile;
length &lenstmt;
infile 'C:\datafile.txt' dsd dlm='09'x;
input &inptstmt;
run;
这让我得到了我需要的东西,但必须有一个更清洁的方式。如果为存储length
和input
语句的变量分配的空间不足,或者语句长度超过最大宏变量长度,则可能会遇到此方法的问题。
有什么想法吗?
答案 0 :(得分:3)
您正在做的是一种相当标准的方法。是的,你可以更仔细地检查一下;我会为这两个陈述分配$32767
,例如,只是为了谨慎。
但是,有一些方法可以改善这一点,这可能会让你担心一些担忧。
首先,一个常见的解决方案是在行级别(就像你那样)构建它,然后使用proc sql
来创建宏变量。这比数据步骤方法有更大的最大长度限制(如果不使用多个变量,则数据步骤方法最大值为$32767
,SQL为64kib时的两倍)。
proc sql;
select catx(' ',colname,'$',collen)
into :lenstmt separated by ' '
from meta; *and similar for inputstmt;
quit;
其次,通过写入文件而不是宏变量,可以超过64k的限制。获取数据步骤,而不是累积然后使用call symput
,将每一行写入temp
文件(或两个)。然后%include
这些文件而不是在输入datastep中使用宏变量 - 是的,你可以在datastep的中间%include
。
还有其他方法,但这两种方法是最常见的,应该适用于大多数用例。其他一些方法包括call execute
,run_macro
,或使用文件打开命令直接处理文件。一般来说,这些都比最常见的两个更复杂或更没用,虽然它们也是可接受的解决方案,在实践中并不常见。
答案 1 :(得分:0)
调用execute show可以提供帮助。
data _null_;
retain start 0;
infile 'c:\metadata.txt' missover end=eof;
if _n_=1 then do;
start=1;
call execute('data final_output; infile "c:\datafile.txt" truncover; input ');
end;
input colname :$8.
collen :8.
;
call execute( '@'|| put(start,8. -l) || ' ' || colname || ' $'|| put(collen,8. -r) ||'. ' );
start=sum(start,collen);
if eof then do;
call execute(';run;');
end;
run;
proc contents data=final_output;run;