LoginSignup
2
1

More than 5 years have passed since last update.

getBytes("MS932") での文字列分割とDBへのinsertではまった話

Last updated at Posted at 2012-10-09

JDK 1.5.0_12, ojdbc14 での話。

DevideString.java
/** 分割開始インデックス */
static final int DIVISION_BYTE_START_INDEX = 0;
/** 分割後文字長 */
static final int DIVISION_BYTE_LENGTH_ADDR = 10;

/**
 * 引数の文字列を[分割後文字長(byte)]以下にカットする。
 * 扱う文字コードは MS932 とする。
 *
 * @param str 文字列(MS932)
 * @return String [分割後文字長(byte)]以下の文字列
 */
String getDivideStringByBytes(String str) {

  if(str == null) {
    return null;
  }

  String result = "";

  try {
    // バイト配列化
    byte[] byteAddr = address.getBytes("MS932");

    if(byteAddr.length > DIVISION_BYTE_START_INDEX) {
      // byte文字列が分割開始インデックス以上の長さである

      if(byteAddr.length > DIVISION_BYTE_START_INDEX + DIVISION_BYTE_LENGTH_ADDR) {
        // byte文字列が分割したい文字長以上の長さである
        result = new String(byteAddr,
                        DIVISION_BYTE_START_INDEX,
                        DIVISION_BYTE_LENGTH_ADDR,
                        "MS932").trim();

      } else {
        // 必要文字長に満たない場合
        result = new String(byteAddr,
                        DIVISION_BYTE_START_INDEX,
                        byteAddr.length - DIVISION_BYTE_START_INDEX, // 長さ:文字長 - 分割(開始)位置
                        "MS932").trim();

      }

      // いわゆる“おまじない”コード(恥)
      // result = new String(result.getBytes("MS932"));

    } catch(UnsupportedEncodingException ue) {
      throw new IllegalArgumentException(ue);

    }

    return result;
  }
}

引数の文字列において、分割される文字列に半角文字(1byte文字)を奇数個含むと、切り口の文字がぶった切られて文字化けする。
例:


"あい うえおかき" → 10 byteで分割 → "あい うえ?"

これをそのままデータベース(oracle)へ insert しようとしたところ、ORA-12899 エラーになった。

データベースの文字コードは Shift_JIS(JA16SJISTILDE)。
カラムに定義された文字長=分割文字長であり、たとえば上記の例であれば:


ORA-12899: 列"DEV"."HOGETABLE"."COLUMN1"の値が大きすぎます(実際: 11、最大: 10)

JDBC(ojdbc14)で insert する直前の値を確認したとき、以下の2パターンが存在した。
前者は末尾の文字が全角の「?」になっている:


1) あい うえ?
2) あい うえ?

1 の場合に ORA-12899 エラーが発生している。

1 は、上記のコードで生成された文字列を用いている。
2 は、上記のコードの おまじない を有効にした場合の文字列を用いている。

1 と 2 の文字列は、(JDBCへ渡す前は)全く同じ文字列に見える:


1) あい うえ? → byte化(MS932):82 a0 82 a2 20 82 a4 82
2) あい うえ? → byte化(MS932):82 a0 82 a2 20 82 a4 82

しかし、String#equals で比較すると「異なる」と判断される。
String#equals は各文字を char で比較する。char にしたときの各文字は 以下のようになる:


1) 'あ' 'い' ' ' 'う' 'え' '・'
2) 'あ' 'い' ' ' 'う' 'え' '?'

そもそもマルチバイトの文字を byte で分割しようとしてるのがアレなのか…
JDBC が余計なことしてくれるのがいけないのか。

別に最後の文字は化けててもいいから、10 byte として突っ込んでくれればいいのに…と思ってしまう。

あと String#equals の挙動も気になる。

2
1
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1