日期:2014-05-16  浏览次数:20995 次

日文字符中常见的乱码情况---正波浪线“~”

在一般的日文字符表示正常的情况下正波浪线“~”任然经常会出现乱码的情况。

数据库参数NLS Database Parameters
NLS_CHARACTERSET????????????????????? JA16SJIS
NLS_NCHAR_CHARACTERSET????? AL16UTF16

一:对于VARCHAR2字段
现象:在页面上输入“~”存入DB后再取出到页面时变成“?”(页面的字符设置为charset=shift-jis)
调查:
1 页面提交后在java中观察编码为\uff5e
2 java中定义一个字符变量“~”观察编码为\uff5e
3 编码为\uff5e的字符存入数据库再取出的编码为\u301c
4 用Object Browser观察数据库中字符都正常
结论:存入数据库时编码发生了变化\uff5e ---> \u301c
解决:取出数据时遍历发现\u301c就转换为\uff5e
???????? public String getString(int columnIndex) throws SQLException {
??????????? // TODO: ~を変更
??????????? String value = rs.getString(columnIndex);
??????????? if (value != null){
???????????????? StringBuffer sbDest = new StringBuffer();
???????????????? char ch;
???????????????? for(int j= 0;j< value.length();j++){
???????????????????? ch = value.charAt(j);
???????????????????? if(ch == 0x301c){
???????????????????????? sbDest.append("\uff5e"); // ~
???????????????????? }else{
???????????????????????? sbDest.append(ch);
???????????????????? }
???????????????? }
???????????????? value = sbDest.toString();
??????????? }

??????????? return value;
??????? }

二:对于NVARCHAR2字段
现象:在页面上输入正波浪线“~”存入DB后再取出到页面时变成反波浪线“?”(页面的字符设置为charset=UTF-8)
用Object Browser工具察看表中的数据 发现是正波浪线“~” 编码为\u301c。(实际上用Object Browser看\u301c???? \uff5e都是正波浪线)
如果用NVARCHAR2字段,那么正确的操作后可以存入\uff5e

试验用表 Products ,表中的列定义如下所示
id - VARCHAR2(10) — 产品 id
lang_id — VARCHAR2(10) — 语言 id
description — NVARCHAR2(2000) — Unicode 编码的产品描述

JDBC 允许 Java 程序访问 Oracle9i 数据库中的 NVARCHAR2 数据类型的列。Oracle JDBC 驱动程序把 SQL NCHAR/NVARCHAR2 列中的数据从本地字符集编码(UTF8 或 AL16UTF16)直接转化为 UTF-16 编码的 Java 字符串。
为此,我们需要把 Java 字符串绑定到一个 NVARCHAR2 列。下面的代码段显示了完成这项任务的代码。

// Get an Oracle preparedstatement
OraclePreparedStatement orastmt =(OraclePreparedStatement)connection.prepareStatement(
"INSERT INTO PRODUCTS VALUES(?,?,?)");
// Bind the 3rd parameter to NVARCHAR2 form so that the data is stored as unicode
orastmt.setFormOfUse(3,OraclePreparedStatement.FORM_NCHAR);
orastmt.setString(1,product.getId());
orastmt.setString(2,product.getLangId());
orastmt.setString(3,product.getDescription());
orastmt.executeUpdate();
orastmt.close();

使用 orastmt.setFormOfUse() 方法来指定列的类型是 NVARCHAR2。确保数据以Unicode 编码存储。

关于NVARCHAR2字段的操作参考:
http://www.oracle.com/technology/sample_code/tech/java/sqlj_jdbc/files/9i_jdbc/NCHARsupport4UnicodeSample/Readme.html

注意这段话:
The only difference in usage between the SQL CHAR and SQL NCHAR datatypes occur in a data bind situation.
The JDBC program must call the setFormOfUse() method to specify if the data is bound for a SQL NCHAR
datatype and it must be called before binding Java variables to SQL NCHAR datatypes.
必须先setFormOfUse再绑定变量。否则存入数据库中的仍是\u301c

Java and Unicode??

?

??????? 一直以来都被Java编程中出现的乱码问题搞得很头痛,不过今天终于有了更深的理解。 其实很简单,Java中的字符都是以Unicode(UTF-16)形式存储的,即使你调用了new String("\uff5e".getBytes("MS932" , "SJIS" ;这样的语句,其实也并非真的就把这个字符从MS932转换成了SJIS编码形式, 只不过是从一个Unicode(MS932编码的全角波浪线在Unicode中对应的字符)变成了SJIS编码的全角波浪线在Unicode中对应的字 符,说白了,转换后还是个Unicode字符。

??????? 但是为什么仍然会出乱码呢?举个简单的例子,某个终端只接受SJIS编码的字符(目前好象还没有哪个终端支持Unicode吧?),如果你通过Java程 序给它传了一个SJIS中该字符在Unicode中对应的字符,那么底层系统可以顺利地将之转换成正确的SJIS编码字符,于是这个终端也就可以正常显示 该字符了;反之,如果你给了一个MS932中该字符在Unicode中对应的字符,而如果它恰好又是一个特殊字符(比如日文中的全角波浪线''~''), 就会出现乱码(因为MS932编码的全角波浪线在Unicode中对应''\uff5e'',而SJIS编码的全角波浪线在Unicode中对应'' \u301c''),示意如下:

''\uff5e''(Unicode,Java程序) -> ?(本地字符集SJIS,终端):NG。因为Unicode字符''\uff5e''并不对应SJIS字符集中的全角波浪线;
''\u301c''(Unicode,Java程序) -> ~(本地字符集SJIS,终端):OK。
??????? 另外,查看了一下