RPAD函数处理特殊汉字时不能正确判断汉字的长度。
特殊汉字“”,为上面一个龙,下面一个天,飞龙在天的意思。还有其他汉字,只以该字举例。
在数据库字符集为UTF-8的情况下执行语句
select RPAD(nvl('',nvl(' ',' ')), 10, nvl(' ',' ')),length(RPAD(nvl('',nvl(' ',' ')), 10, nvl(' ',' '))) from dual;
RPAD(NVL('',NVL('','')),10,N LENGTH(RPAD(NVL('',NVL('',''
------------------------------ ------------------------------
10
SQL> select RPAD(nvl('淞',nvl(' ',' ')), 10, nvl(' ',' ')),length(RPAD(nvl('淞',nvl(' ',' ')), 10, nvl(' ',' '))) from dual;
RPAD(NVL('淞',NVL('','')),10,N LENGTH(RPAD(NVL('淞',NVL('',''
------------------------------ ------------------------------
淞 9
汉字参数不同,得到的结果不同。
对于“淞”字,结果正常,补了8个空格。
而汉字“”,补了9个空格,oracle将该字长度判断为1了。
使用函数to_nchar将字符先转换一下就不会有问题了。
select RPAD(nvl(to_nchar(''),nvl(' ',' ')), 10, nvl(' ',' ')),length(RPAD(nvl(to_nchar(''),nvl(' ',' ')), 10, nvl(' ',' '))) from dual;
RPAD(NVL(TO_NCHAR(''),NVL('' LENGTH(RPAD(NVL(TO_NCHAR('')
------------------------------ ------------------------------
9
数据参数
NLS_CHARACTERSET='UTF8',
NLS_LANGUAGE='SIMPLIFIED CHINESE' NLS_TERRITORY='CHINA' NLS_CURRENCY='¥' NLS_ISO_CURRENCY='CHINA'
NLS_NUMERIC_CHARACTERS='.,' NLS_DATE_FORMAT='DD-MON-RR' NLS_DATE_LANGUAGE='SIMPLIFIED CHINESE' NLS_SORT='BINARY'
其他同样问题测试,
地址: http://www.itpub.net/viewthread.php?tid=1091387&extra=&page=1
DECLARE
C_STR VARCHAR2(1000) := '在UTF8字符集下对中文和特殊字符如⑥的输出测试';
LEN INTEGER := 50;
C_STR1 VARCHAR2(1000);
C_RESULT VARCHAR2(1000);
BEGIN
DBMS_OUTPUT.PUT_LINE('UTF8 STR LENGTH=' || LENGTH(C_STR));
DBMS_OUTPUT.PUT_LINE('UTF8 STR LENGTHB=' || LENGTHB(C_STR));
DBMS_OUTPUT.PUT_LINE('gbk STR LENGTH=' || LENGTH(CONVERT(C_STR, 'zhs16gbk', 'UTF8')));
DBMS_OUTPUT.PUT_LINE('gbk STR LENGTHB=' || LENGTHB(CONVERT(C_STR, 'zhs16gbk', 'UTF8')));
--oracle原来的rpad
C_RESULT := RPAD(C_STR, LEN, '-');
DBMS_OUTPUT.PUT_LINE('LENGTH=' || LENGTH(C_RESULT) ||',LENGTHB=' || LENGTHB(C_RESULT) || ',RESULT=' || C_RESULT);
--自己处理的
C_RESULT := C_STR || LPAD('-', LEN - LENGTHB(CONVERT(C_STR, 'zhs16gbk', 'UTF8')), '-');
DBMS_OUTPUT.PUT_LINE('LENGTH=' || LENGTH(C_RESULT) ||',LENGTHB=' || LENGTHB(C_RESULT) || ',RESULT=' || C_RESULT);
END;
/
--输出结果:
UTF8 STR LENGTH=24
UTF8 STR LENGTHB=64
gbk STR LENGTH=27
gbk STR LENGTHB=44
LENGTH=31,LENGTHB=71,RESULT=在UTF8字符集下对中文和特殊字符如⑥的输出测试-------
LENGTH=30,LENGTHB=70,RESULT=在UTF8字符集下对中文和特殊字符如⑥的输出测试------
测试的目的就是想将数据库中存放的数据按定长写入到文本中,数据库为oracle 10.2.0.4.0,服务器字符集为UFT8,生成的文本要求是GBK格式,不足位要补足。
在字符下使用RPAD和LPAD都没问题,但遇上特殊字符就麻烦了,生成的文本总会多出几个特殊字符的占位,如上面测试的结果,只有一个特殊字符就多占一位,如果两个,则多占两位。
有几个问题没太明白:
1、从结果反推,RPAD(str,len,pad)中的len计算是将字符当一个占位,汉字当两个占位,特殊字符还是当一个占位处理,而实际上特殊字符是要占两位的(GBK下),所以得出结果比实际的要长N位,N=特殊字符的个数,那么这个是属于oracle的问题吗,还是oracle没有按unicode去处理?
2、SELECT LENGTH(CONVERT('集', 'zhs16gbk', 'UTF8')),LENGTH('集'),CONVERT('集', 'zhs16gbk', 'UTF8') FROM dual;
得出的结果,第一个是2,第二个是1,第三个是'集',oracle的length不是不管中文还是字符,都当一个字节处理吗,那么这个'集'字经过一次转换后,怎么成两个字节了呢,是因为'集'的编码从UTF8转到GBK后正好是两个字吗,可实际显示还是一个'集'字。
3、一眼看出,得出的结果不管是LENGTH还是LENGTH都与我实际要求的LEN长度不一样,但第二条的实际结果就是希望得到的结果,是不是也会让初学者摸不着头脑呢?