sasmysql乱码_在SAS中如何解决中⽂乱码问题
在SAS中如何解决中⽂乱码问题
在⽇常的数据分析处理⼯作中,不可避免的经常会和中⽂字符串打交道。如果数据中有乱码,该如何处理?...
烦⼈的问题
在⽇常⼯作中,使⽤SAS进⾏数据处理是很正常的事情,不可避免的经常会和中⽂字符串打交道。不知道各位在使⽤EG的过程中,打开数据集查看数据的时候,有没有遇到过以下问题?
(虽然我也只是偶尔遇到,但已经被折磨好⼏年!)
SAS Enterprise Guide 5.1
SAS Enterprise Guide 6.1
SAS Enterprise Guide 7.1
不同的版本提⽰的错误形式不完全⼀样,但出现的原因却是⼀模⼀样的(下⾯有情景再现的过程)。仔细查看,不难发现真正的错误信息都是⼀样的,主要是:
“Failed to transcode data from U_EUC_CN_CE to U_UTF8_CE encoding because it contained characters wihch are not supported by your SAS session encoding. Please review your encoding= and locale= SAS system options to ensure that they can accommodate tje data that you want to process.”
这段话是什么意思呢?其实就是上⾯EG 7.1版本的错误提⽰的中⽂描述。简⽽⾔之,就是告诉你数据中有⽆法处理的编码数据。
session数据错误是什么意思问题的严重性
出现这个问题,仅仅是不能打开查看数据吗?不是!如果出现这个问题,意味着你基本不能⽤这个数据进⾏后续的分析了。只要进⾏的处理或者分析涉及到该有问题的字段就会提⽰上⾯的这个错误信息,阴魂不散,挥之不去。
怎么办
最简单粗暴的办法就是不⽤图形化的⼯具EG,⽤最经典的Base⼯具就没有这个问题了,⼀劳永逸。⽽有时候没法不⽤EG的时候怎么办?⽐如我是⽤EG连着SAS服务器进⾏处理的,该怎么办?
⾄于为什么EG会出现这个问题,⽽Base界⾯没有这个问题呢?主要是因为软件的底层设计⽽导致的,这个编码问题说⼤不⼤,说⼩不⼩;忽略了就可以正常使⽤,如果不忽略,那么它就是⼀个问题。下⾯会对这个问题进⾏再现,剖析其原因,你就明⽩了。
问题重现
当我第⼀次遇到这个问题的时候,想不明⽩,就去google搜索错误信息,到的⽂档资料基本都是说编码或者地区的设置问题。意思就是说数据的编码跟现有的SAS环境的编码不⼀致,也就是上⾯错误信息当中提⽰的。要你通过option encoding= locale=; 修改到正确的编码及地区,就可以解决问题了。可是我的环境是没有任何问题的,数据也是同样的环境⽣成的。经过了⼏次的研究,最后搞清楚了,这个问题是由于中⽂被截断⽽导致的。
(下⽂需要有⼀定的IT基础知识,不懂的童鞋,可度娘有关数据存储、数据编码⽅⾯的知识;只要⼤概明⽩数据是怎么在计算机中存储及还原的就OK了)
具体来说:在GBK编码中(SAS中⽂的默认编码⽅式),⼀个汉字是占两个字节。由于各种原因,在存储数据的时候某个汉字只存储了其中的⼀个字节,另⼀个字节丢失了。那么就导致这个字节没法还原,不知道是什么东西(因为少⼀个字节的信息)。所以才会有上⾯的错误提⽰:数据中包含当前SAS会话编码不⽀持的编码数据。
我们可以⽤下⾯简单的程序来再现这个问题(在EG中运⾏这段程序,在Base中是可以正常查看数据的,但只显⽰“你好”。)
data test;
length str $ 5;
str="你好啊";
run;
当运⾏完这段程序,打开test数据集查看的时候,就出现上⾯的错误信息:
“你好啊”三个汉字需要6个字节去存储,⽽str事先定义了长度为5个字节,这就导致只存储了2.5个汉字;⽽存储的这0.5个汉字信息由于没法显⽰,所以才导致上⾯提⽰的编码问题。
进⼀步来看看底层的信息(⼗六进制编码):
data _null_;
length str1 $ 5 str2 $ 6;
str1="你好啊";
str2="你好啊";
put str1 $hex12.;
put str2 $hex12.;
run;
⽇志信息:
从上⾯的⽇志信息可以看到,就是因为少存储了“A1”这个字节信息,导致“B0”这个字节⽆法解码,⽆法正常显⽰。
额外补充(懂的⼈就此略过):
汉字“你”的GBK编码,⼗进制为50403,⼗六进制为C4E3
汉字“好”的GBK编码,⼗进制为47811,⼗六进制为BAC3
汉字“啊”的GBK编码,⼗进制为45217,⼗六进制为B0A1有⼈可能会想:英⽂字符就是⼀个字节存储的,⼀个字节也能显⽰出来;为什么这⾥的⼀个字节就出问题了?
这就涉及到编码范围的问题了,英⽂字符是ASCII编码。通过查看标准的ASCII码表就可发现,最⼤的编码⼗进制为127,⼗六进制为7F;⽽B0是远⼤于7F的,超出了ASCII的编码范围,因此⽆法显⽰。
如果你够仔细,你就会发现,其实在EG的错误提⽰中,就包含了这段出问题的⼗六进制编码信息:c4 e3 ba c3 b0。
解决⽅案
问题的原因既然搞清楚了,那么如何解决的思路就很清晰了。说⽩了就是出字符串中有中⽂截断的地⽅,然后将这半个汉字的信息直接删除就没问题了。
以前⾯⽣成的test数据为例,str的最后⼀个字节包含了半个汉字信息,只要将最后⼀个字节删掉就OK了。
data test2;
set test;
code_before=put(str,$hex10.);
str=substr(str,1,4);
code_after=put(str,$hex10.);
run;
如上所⽰,经过处理后,可以正常的显⽰数据了。
(注:code_after中最后⼀个字节“20”是空格的⼗六进制编码。字符变量中多余的字节,SAS默认⽤空格来填充。因此“你好”两个汉字占4个字节,剩余⼀个字节就是空格。)
虽然解决⽅法很清晰,想起来也很简单,但要实现起来还不是那么容易。上⾯的情况是特例,我们明显知道在哪个地⽅有问题,直接处理就OK。
但通常情况下,我们是不知道在字符串的具体哪个地⽅有截断,也不知道是哪些观测有截断的问题;⽽且每条观测中被截断的位置也不⼀定都⼀样,甚⾄也不知道截断的数据后⾯有没有其他字符数据。⾯对这么多不确定,该如何解决?
下⾯,提供⼀种思路,有兴趣的童鞋可以⾃由发挥,去解决这个问题。
解决思路
⾸先,GBK编码⽅案中,总体的编码是有范围的,从8140~FEFE。其中⾸字节在81~FE之间,尾字节在40~FE之间,剔除xx7F⼀条线;总计23940个码位,共收⼊21886个汉字和图形符号,其中汉字21003个,图形符号883个。
其次,ASCII编码的范围是从00~7F,共计128个码位,收⼊⼤⼩写英⽂字母、数字、符号、及特殊控制字符。其中可显⽰的编码范围为20~7E。
基于上⾯的这些信息,就可以从⼗六进制编码⼊⼿,逐个去判断识别,进⽽到存在截断的位置,然后将其处理掉。记得要考虑以下多种情况:数据分析师培训
截断情况出现在字符串末尾
截断情况出现在字符串中间,且后⾯紧跟英⽂字母
截断情况出现在字符串中间,且后⾯紧跟完整的汉字
完 谢谢观看
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论