恼人的问题
在日常工作中,使用SAS进行数据处理是家常便饭,难免要经常和中文字符串打交道。 不知大家在使用EG的过程中打开数据集查看数据时是否遇到过以下问题?
(虽然只是偶尔遇到,但我已经被折磨好几年了!)
SAS 企业指南 5.1
SAS 企业指南 6.1
SAS 企业指南 7.1
不同版本提示的错误形式不完全相同,但出现的原因完全相同(场景再现过程如下图)。 仔细查看后不难发现,真正的报错信息都是一样的,主要是:
“无法将数据从 U_EUC_CN_CE 编码转码为 U_UTF8_CE 编码,因为它包含您的 SAS 会话编码不支持的字符。 请检查您的 encoding= 和 locale= SAS 系统选项1个汉字占几个字节,以确保它们可以容纳您要处理的数据。”
这段话是什么意思? 其实就是上面EG 7.1版本的错误信息的中文描述。 简而言之,它告诉你数据中有未处理的编码数据。
问题的严重性
出现这个问题,难道只是无法打开查看数据? 不! 如果出现这个问题,说明你基本上不能用这个数据进行后续的分析。 只要处理或分析涉及到有问题的字段,就会提示上面的错误信息,鬼影缠身,挥之不去。
该怎么办
最简单粗暴的办法就是不使用图形化工具EG,而使用最经典的Base工具一劳永逸地解决这个问题。 有时当您无法使用 EG 时该怎么办? 比如我用EG连接SAS服务器进行处理,怎么办?
至于为什么EG会出现这个问题,而Base界面不会? 主要是软件的底层设计造成的。 这个编码问题不大不小; 如果忽略,则可以正常使用。 如果它不被忽视,那就是一个问题。 下面将重现这个问题,分析其原因,你就明白了。
问题重现
第一次遇到这个问题的时候,想不通,就去谷歌搜索报错信息,查到的文档基本都是关于编码或者区域设置的。 意思是数据的编码与现有SAS环境的编码不一致,就是上面错误信息中的提示。 如果通过选项 encoding= locale=; 更改为正确的编码和区域,则可以解决问题。 但是我的环境没有问题,数据也是在同一个环境下生成的。 经过多次研究,我终于弄清楚这个问题是由截断中文引起的。
(以下内容需要一定的IT基础知识,不懂的童鞋,可以了解一下数据存储和数据编码的知识;只要大致了解数据在计算机中是如何存储和恢复的,就可以了好的)
具体来说:在GBK编码(SAS中文默认的编码方式)中,一个汉字占用两个字节。 由于种种原因,在存储数据时,只存储了某个汉字的一个字节,而另一个字节丢失了。 那么这个字节就无法恢复了,也不知道是什么(因为少了一个字节的信息)。 这就是为什么会出现上述错误消息:数据包含当前 SAS 会话编码不支持的编码数据。
我们可以用下面这个简单的程序来重现这个问题(在EG中运行这个程序,在Base中可以正常查看数据,但是只显示“Hello”。)
数据测试;
长度 str $5;
海峡=“你好”;
跑步;
运行该程序,打开测试数据集查看后,出现如上错误信息:
“你好”三个汉字需要6个字节存储,而str预先定义了5个字节的长度,导致只存储了2.5个汉字; 而存储的0.5个汉字信息无法显示,所以导致了上面提示的编码问题。
让我们仔细看看底层信息(十六进制编码):
数据_空_;
长度 str1 $5 str2 $6;
str1="你好";
str2="你好";
把 str1 $hex12.;
把 str2 $hex12.;
跑步;
日志信息:
从上面的日志信息可以看出,由于缺少“A1”的字节信息,导致“B0”字节无法正常解码显示。
补充说明(懂的略过):
可能有人会想:英文字符用一个字节存储,也可以显示一个字节; 为什么这里有一个字节有问题?
这就涉及到编码范围的问题,英文字符都是ASCII编码。 通过查看标准的ASCII码表,可以发现编码后的十进制最大为127,十六进制为7F; 而B0比7F大很多,超出了ASCII编码范围,所以无法显示。
如果你足够细心,你会发现EG的报错信息中包含了问题的十六进制编码信息:c4 e3 ba c3 b0。
解决方案
既然弄清楚了问题的原因,那么如何解决的思路就很清晰了。 说白了,就是找出字符串中哪里有中文截断,然后直接删除这半个汉字的信息,就没有问题了。
以前面生成的测试数据为例,str的最后一个字节包含半个汉字信息,只要删除最后一个字节就OK了。
数据测试2;
设置测试;
code_before=put(str,$hex10.);
海峡=子海峡(海峡,1,4);
code_after=put(str,$hex10.);
跑步;
如上图,经过处理后,数据可以正常显示。
(注:code_after中最后一个字节“20”为空格的十六进制编码,SAS默认将字符变量中多出的字节用空格填充。因此“你好”这两个汉字占用4个字节,剩下的一个字节是一个空格。)
虽然解决方案思路清晰且简单,但实施起来并不容易。 上述情况属于特例。 我们明明知道哪里出了问题,直接去处理就OK了。
但通常情况下,我们并不知道字符串在哪里被截断,也不知道哪些观测值存在截断问题; 并且每次观察中截断的位置不一定相同,我们甚至不知道截断数据之后没有其他字符数据。 面对如此多的不确定因素,如何解决?
下面提供一个思路,感兴趣的童鞋可以自由发挥来解决这个问题。
解决方案
首先,在GBK编码方案中,整体的编码范围是从8140到FEFE。 其中,第一个字节在81~FE之间,最后一个字节在40~FE之间,排除xx7F行; 共23940个码位,共收录汉字和图形符号21886个,其中汉字21003个,图形符号883个。
其次,ASCII编码的范围是从00到7F,共128个码位,包括大小写英文字母、数字、符号和特殊控制字符。 可显示的代码范围为20~7E。
根据以上信息,可以从十六进制码入手,逐一判断识别,然后找到有截断的位置,再进行处理。 请记住考虑以下情况:
在下一篇文章中,将会有完整详解的SAS代码来解决这个问题。 欢迎小伙伴们用自己的代码交流,敬请期待。
(有兴趣的可以发邮件到下方邮箱,下期分享给大家)
关于作者:
2010年在大学偶遇SAS,相恋6年,现在进入七年之痒阶段(捂脸)。 这么多年,我对SAS又爱又恨,但从未离开过它。 人们说这是真爱,但很难忘记。 我绝对热爱 SAS。 我有统计学背景。 在遇到 SAS 之前,我因为 C 和 C++ 课程而爱上了编程。 从一个电脑白痴做起,走上IT之路,曾经以为自己是在往程序员的方向发展。 结果后来遇到了我生命中最重要的人之一:雷教授,他来到我们学校,给我们带来了SAS,给我们带来了新的知识,从此我们又增加了一门数据挖掘的课程。 雷教授把我从程序员的行列救了出来,带我进入了这个行业。
从SAS 9.1开始,我一度认为SAS只是一个程序,一个日志,一个结果窗口。 后来才知道SAS庞大,产品线丰富,看得我眼花缭乱。 工作后,我真正了解了SAS。 我开始了解EG和EM的一键版产品; 后来又来到了服务器版的产品,安装部署配置,接触了SMC,SDM; 然后来到解决方案。 不同的解决方案是不同的产品组合。 ,再加上不同的部署方案; 各类工具产品:数据集成工作室、预测工作室、数据管理工作室等各类工作室,可视化分析、社交网络分析、客户智能工作室等各类Web产品。 所以我对SAS的了解越来越多,但是和它所有的产品线相比,这只是皮毛中的皮毛!
除了日常的分析和挖掘工作1个汉字占几个字节,由于工作需要,我还做了很多基于SAS的二次开发工作,主要是.Net开发。 大部分是基于EG的功能插件开发,基于SAS IT的客户端开发; 还有一些服务器程序调度工作。 这些也离不开大学里学的C和C++。 上学的时候还怪我们学院开设C、C++等与专业无关的课程,现在看来不对了。 所以我有一个深切的感受:多学点知识总是对的,在以后的生活和工作中一定会派上用场的。
好像说的有点多了,最后希望我的经验可以帮助到大家。 SAS 是一条不归路。 一旦踏上,就无法回头,因为有太多的事情等着你。 有问题可以在SAS中文论坛微信群@我进行更多交流。 也可以邮箱:slash.xin@hotmail.com
12月原创好文回顾,请点击阅读: