4月 19, 2011

Posted by in 分享 | 92 条评论

SAS中定义字符长度问题

前段时间翻看SASOR上的老帖子,在这个帖子ahuigeqkaiwei 讨论了下SAS中定义字符长度的问题,觉得挺有意思也挺有用处,摘录如下:

ahuige

1.第一个讨厌的特性,变量按第一次赋值决定变量的长度。

1
2
3
4
5
data xx;
x='ab';
x='ab'||'c';
put x=;
run;

以上的语句,在log窗中可以看到,x的值依然是’ab’;这会让一个使用过其他语言写过这种天经地义的正确写法但又在sas中得到这种结果的人不知所措

ahuige

然后现在会有sas的卫道者跳出来说,这有什么,一个变量应该先定义长度,然后再赋值。下面的方法可以解决这个问题

1
2
3
4
5
6
data xx;
length x$8.;*这里加一个定义长度;
x='ab';
x='ab'||'c';
put x=;
run;

这个问题的确解决了,log窗里可以看到这里x=’abc’
好,现在初学者认为他已经了解了解决这个问题的方法。但是,下面的pitfall又来了。

1
2
3
4
5
6
data xx;
length x$8;
x='ab';
x='x||'c';
put x=;
run;

作者的本意是想得到x=’abc’,但是log里面又显示的是x=’ab’,作者还是又跳进陷阱了。

ahuige

卫道士又跳出来说,这个是因为sas自动给ab后面加上6个空格,
所以,应该再加一个trim函数.

1
2
3
4
5
6
data xx;
length x$8.;
x='ab';
x=trim(x)||'c';
put x=;
run;

上面的语句又解决问题了。log窗显示x=’abc’
好,后面的问题又来了。你说后面自动加空格,那你你长度当然就是固定的8了。看看我下面的语句

1
2
3
4
5
6
7
8
9
10
11
data xx;
length x$8.;
x='ab';
l=length(x);
put x=;
put l=;
x=trim(x)||'c';
l=length(x);
put x=;
put l=;
run;

结果他的结果是第一个l表示长度为2,第二个l又表示长度为3.那空格为何又不算长度???

ahuige

卫道者又说,空格嘛,不算长度是应该的。
好,问题又来了。我试了试下面的语句

1
2
3
4
5
6
7
data xx;
len1=length('x');
len2=length(' ____');*这里的4个_其实是空格;为了怕sasor网站把空格压缩了。
len2=length('_');*这里的1个_其实是空格;为了怕sasor网站把空格压缩了。
len3=length('');
put _all_;
run;

结果,不但’x’长度为1,4个空格长度为1,1个空格长度为1,连TMD空值长度都为1.我说怎么上次用判断一个字符的长度为零来判断是不是空值没得效,搞得我半死不活

上面有俩个len2可能是ahuige笔误,可能是len1,len2,len3,len4,如下:

1
2
3
4
5
6
7
data xx;
	len1=length('x');
	len2=length('    ');
	len3=length(' ');
	len4=length('');
	put _all_;
run;

qkaiwei

1 SAS的字符变量默认的字符长度是8位,如果默认定义一个str=’ab’,str实际储存’ab____’,不足位空格补全,类似数据库中的定长型字段(char),当合并两个字符串时,str||str的实际结果是’ab____ab____’,看起来是’ab ab’。如果把这个结果赋值给一个字符变量x,而x变量没有用length改变默认长度,系统会将’ab____ab____’的前8位赋值给x,所以x 的值位’ab____’,看起来就是’ab’.

2 当计算非空字符串的长度时,首尾空格是被忽略的,全空字符串,SAS会将其看做一个空字符,至于length(”)的长度也为1,其实在SAS中”与”是一回事”=’ ‘,无论第二个空串中有几个空格。

ahuige

管理员啊。你的第一个段落我还是有一点点不认同,sas的默认长度可能在input时是8,但直接赋值是按第一次碰到的长度定义。比如我举的第一个例子

1
2
3
4
5
6
7
8
data xx;
x='ab';
x='ab'||'c';
put x=;
run;
 
proc contents;
run;

////////////////以下是输出,可以看出length为2
# Variable Type Len Pos
1 x Char 2 0

而且如果默认是8的话,x=’ab’||’c’没有理由不等于’abc’的。

其他几个例子就不说了嘛,你说得很清楚了。但这些与众不同的特性我想你没有理由说它们是优秀的吧?(比如第二段,想想,你将如何麻烦的去生成多个字符字段的一些有一点点变化的连接,其中的空格个数比较等控制更是讨厌)

qkaiwei

WO,对了,我忘了,我前几天还碰到这个问题。学艺不精啊!hihi,你以后叫我混混就是了。
你也别管它为什么,就像‘垃圾’为什么是‘土+立+土+及’,你想过没有?问过为什么没有?

 

原帖出处:
http://sasor.feoh.net/viewtopic.php?f=1&t=618&start=0

  1. 呵呵,有意思!!
    昨天在人大上看到的一个帖子:
    data _null_;
    y=10600001;
    z=substr(y,7,6);
    put z=;
    run;
    所得结果:
    z=600001

    [回复]

    hssnow 回复:

    哈哈,刚搜了一下,nice,学习了啊

    [回复]

  2. 哈哈,好古老的帖啊,多年前见过,还有印象的。

    其实很多SAS初学者,特别是学过其他语言的,对SAS变量长度一经定义后不能被改变的规则表示不理解,实际中使用碰到出错,并且对此很愤慨。

    其实每个语言有每个语言的一套,不可强求什么语言都是一样的规则,既然用到这门语言,那就按规则来玩。

    [回复]

  3. 看了帖子的第二页,发现我也参与讨论了。

    [回复]

    hssnow 回复:

    嘿嘿,前辈们当年可是各种给力啊

    [回复]

  4. 不知道import中是否可以定义变量的长度,如下面语句:
    PROC IMPORT OUT= WORK.Custer
    DATAFILE= “C:\Documents and Settings\Administrator\桌面\Custmer_Views.csv”
    DBMS=CSV REPLACE;
    GETNAMES=YES;
    DATAROW=2;
    RUN;
    我想定义变量的长度,不知道如何定义?

    [回复]

    hssnow 回复:

    用import时好像是不行的,SAS是自动扫描数据行来决定变量的属性和长度的。

    [回复]

  5. 今天就遇到这个问题了,excel导入的时候字符变量的值被截断了

    [回复]

发表评论

返回顶部