当我尝试将字符串重新编码为另一个字符串时,我没有得到预期的结果:
数据:
data test1;
input C_TNM_T $ ;
datalines;
AZCD11
AZCD10
AZCD12
AZCD13
AZCD131
AZCD13A
AZCD13A1
AZCD13A2
AZCD13B
AZCD13B1
AZCD13B2
AZCD13C
AZCD14
;
我试图将AZCD12重新编码为':
data test2;
set test1;
if C_TNM_T = 'AZCD11' then _33_cT_temp = 'a' ;
if C_TNM_T = 'AZCD10' then _33_cT_temp = '0' ;
if C_TNM_T = 'AZCD12' then _33_cT_temp = 'is' ;
run;
但是' AZCD12'而是重新编码为' i' (如下图所示)。这是为什么?
如果我只记录了AZCD12'结果是我的预期:
data test2;
set test1;
if C_TNM_T = 'AZCD12' then _33_cT_temp = 'is' ;
run;
PS。如果您有关于更好地描述问题的建议,请随意编辑标题。
答案 0 :(得分:2)
这并不意外。
由于您没有为_33_cT_temp
变量指定长度,因此长度和类型会自动分配给程序遇到的第一个值,在这种情况下:
then _33_cT_temp = 'a' ;
所以_33_cT_temp
将是char($),长度为1(' a'只有一个字符)。
当您尝试分配'是'值,这将被截断,试图适合长度为1的变量。
解决方案和良好的编程实践也是在设置pdv,数据之后和设置之前定义新变量的长度和类型。
data new;
length _33_cT_temp $2;
set old;
[your statements]
run;
在第二种情况下,您具有正确的结果(未截断),因为第一个指定的值的长度为2,因此该变量将为长度为2的char。
自动长度和类型分配的其他情况可能是: 如果您没有指定长度和类型,并且您将变量设置为等于另一个变量(new = old),则新变量的类型和长度将与旧变量相同。 如果您没有指定长度并使用CAT字符串函数指定值,则默认长度将为200.未初始化的vars缺少数字。 等等...
答案 1 :(得分:2)
这是所有SAS用户在某一时刻都会面临的经典难题,由于SAS与其他语言相比如何运作,因此可能会有点混乱。为新变量_33_cT_temp
指定值时,也会同时初始化它。 SAS将使用分配的第一个值的长度初始化变量,并根据分配给它的值确定它是字符串还是数字。
考虑在该程序中初始化的三个变量:
data test;
NumVar = 50;
CharVar1 = 'A';
CharVar2 = 'AB';
run;
在此数据集上运行PROC CONTENTS
将显示:
Variable Type Len
CharVar1 Char 1
CharVar2 Char 2
NumVar Num 8
这些是SAS在初始化时提供的默认分配。请注意,数字变量自动分配了8个字节的长度,而字符变量则根据长度而不同。任何后续作业> CharVar1
中的1个字符(或字节)将导致将值截断为1个字符。这就是您在数据中看到这种现象的原因。
在您的第一个test2
数据集中,首先为_33_cT_temp
分配值a
。与上述程序一样,这会将其初始化为1,将下一个值is
截断为i
。在您的第二个test2
数据集中,_33_cT_temp
首先被赋值为is
,其长度为2.
要解决此问题,您需要首先使用您认为的最大长度初始化字符变量。空间不再是一个问题,所以你可以更自由地完成任务。当然,您可以扫描列以找到最大可能的长度,但如果您有大量的数据集而不是大量的计算资源,那么它就不值得。
您可以在程序的最开头或在分配变量的第一个值之前使用length
语句设置长度:
data test2;
set test1;
length _33_cT_temp $2.;
if(C_TNM_T = 'AZCD11') then _33_cT_temp = 'a';
if(C_TNM_T = 'AZCD10') then _33_cT_temp = '0';
if(C_TNM_T = 'AZCD12') then _33_cT_temp = 'is;
run;
您还可以使用length
语句来设置变量的列顺序。列按初始化变量的顺序设置。如果您将上述程序更改为:
data test2;
length _33_cT_temp $2.;
set test1;
if(C_TNM_T = 'AZCD11') then _33_cT_temp = 'a';
if(C_TNM_T = 'AZCD10') then _33_cT_temp = '0';
if(C_TNM_T = 'AZCD12') then _33_cT_temp = 'is;
run;
您会发现_33_cT_temp
是第一位的。我经常使用这个技巧,特别是对于包含大量ID变量或日期的大型数据集。例如:
data a;
length Date Hour Minute Second Cust_ID Trans_ID 8.
First_Name Last_Name $30.;
set have;
<code>
run;