重新编码字符串时SAS意外截断

时间:2015-09-30 14:03:39

标签: sas

当我尝试将字符串重新编码为另一个字符串时,我没有得到预期的结果:

数据:

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' (如下图所示)。这是为什么?

enter image description here

如果我只记录了AZCD12'结果是我的预期:

data test2;
set test1;

 if C_TNM_T = 'AZCD12'   then _33_cT_temp   =  'is'  ;
run;

enter image description here

PS。如果您有关于更好地描述问题的建议,请随意编辑标题。

2 个答案:

答案 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;
相关问题