在sas中用find和index来处理中文字符匹配搜索会有问题,一般而言,建议where 来筛选,如果要标识,可以用case when,或者在find和index的结果在进行一层逻辑判断
bug如下:
- data _null_;
- a='人大经济论坛赛仕专版';
- c=find(a,'厶');
- b=index(a,'厶');
- put c b;
- run;
复制代码
可以得到结果是c和b为10.
原因在于一个中文字符为两个字节16位,而find和index内部机制是来搜索所要字符的ASCII码,因此会有这样的问题:一个中文字符的第二个字节和它紧跟的另一个字符的第一个字节,如将两者组合会有产生另一个中文字符,而这个中文字符又恰巧是需要查找的字符,导致结果并非是需要的。
此例中:
“论”ascII码:第一个字节:C2,第二个字节: DB
“坛”ascii码:第一个字节:CC,第二个字节: B3
而DB和CC却可以组成另一个中文:“厶”
因此这段中文虽然不含“厶”,但却含有其对应的ASCII,而find和index无法对这ASCII码是否同属一个中文字符进行判断,因此仍然会返回非零值。
所以如果对大量文本进行中文查找时,由于待查找量的庞大,无法预估是否会发生这样的情况,保守起见不会使用find和index函数。
而where 语句筛选无论是contains还是like都不会有这样的问题,如果需要打标识而不是筛选,可以使用proc sql的case when
index和find函数虽然返回非零值,但是在某些情况下再加一层判断也是可以进行处理的,因为index和find默认返回是字符所在字符串的位置,因此如果对
全中文字符串进行查找时,返回的值一定是个奇数,原因就是中文是两个字节,所以起始字节的位置一定是奇数,可以对返回值是否为奇数判断,而如果返回偶数,便就是上面陈述的情况了。而如果目标字符串不是全中文,含有数字或者西文字符,则无法使用奇数的判断条件,非中文字符的一个字节会改变其它中文字符所在的位置。因此字符串中并不是所有中文都是以奇数为起始位的。
- proc sql;
- create table ... as
- select
- case when string contains '天健'
- or string contains '亚太'
- or string contains '晋元' then 1 else 0 end as a
- ....
- from
- ....
- ;
- quit;
复制代码