電子書籍の厳選無料作品が豊富!

文字コードのチェックについて質問です。

検索した所、下記の質問で同じような質問がでていたので参考に作ってみたのですが
java.lang.ArrayIndexOutOfBoundsException
になってしまい動作しません。
charに変換するときに2byte使う条件が違っているのだと思うのですがよくわかりませんでした。
http://okwave.jp/qa1754723.html
↑参考にした質問

入力された文字に対象となる文字コードが含まれているかをUnicodeではなくてSJISのコードで調べたいのですがどうすればよいか教えてくれませんか?
うまく動作しなかったのは下記のコードです。
引数で与えられた文字列にSJISの8740~879c、ed40~effc、fa40~fc4b(機種依存文字と外字)
が含まれていたらエラーにするようなメソッドです。

---
private boolean checkChar(String target) {
byte charArray[] = charArray = target.getBytes("MS932");
for (int i = 0; i < charArray.length; i++) {
byte charByte = charArray[i];
char targetChar;
if (charByte >= 128) {
targetChar = (char) charByte;
} else {
targetChar = (char) (charByte * 0x100 + charArray[i + 1]);
i++;
}
if (0x8740 <= targetChar && targetChar <= 0x879c) {
// エラー処理
return false;
}
if (0xed40 <= targetChar && targetChar <= 0xeffc) {
// エラー処理
return false;
}
if(0xfa40 <= targetChar && targetChar <= 0xec4b) {
// エラー処理
return false;
}
}
return true;
}
---

A 回答 (3件)

Java はあまり使ってないので間違っているかもしれませんが…



Java の byte は符号付で文字コード範囲を比較する際に扱いにくいので,

> byte charByte = charArray[i];

とするよりも,

int charByte = charArray[i] & 0xFF;

とする方がいいと思います.


// charByte が SJIS 2バイト文字の第1バイトのときそのときに限り真を返す.
private static boolean isLeadByte(int charByte)
{
  return ((0x81 <= charByte) && (charByte <= 0x9F)) ||
         ((0xE0 <= charByte) && (charByte <= 0xFC));
}

// charByte が SJIS 2バイト文字の第2バイトのときそのときに限り真を返す.
private static boolean isTrailByte(int charByte)
{
  return (0x40 <= charByte) && (charByte <= 0xFC) && (charByte != 0x7F);
}

private boolean checkChar(String target) {
  byte charArray[] = charArray = target.getBytes("MS932");
  for(int i = 0; i < charArray.length; i++) {
    int charByte = charArray[i] & 0xFF;
    int charByte2, targetChar;

    if(isLeadByte(charByte)) {
      // charByte が2バイト文字の第1バイトの場合
      if(++i >= charArray.length) {
        // 第2バイトが存在しない場合:エラー
        return false;
      }
      charByte2 = charArray[i] & 0xFF;
      if(!isTrailByte(charByte2)) {
        // 第2バイトが不正:エラー
        return false;
      }
      targetChar = (charByte << 8) | charByte2;

      if((0x8740 <= targetChar) && (targetChar <= 0x879E)) {
        // 13区 (NEC特殊文字の場合):エラー
        return false;
      }
      if((0xED40 <= targetChar) && (targetChar <= 0xEFFC)) {
        // 89~92区 (NEC選定IBM拡張文字) の場合:エラー
        return false;
      }
      if((0xFA40 <= targetChar) && ((targetChar <= 0xEC4B)) {
        // 115~119区 (IBM拡張文字) の場合:エラー
        return false;
      }
    }
  }
  return true;
}

でどうでしょうか? (コンパイルは通してません.)


あと,

> SJISの8740~879c、ed40~effc、fa40~fc4b(機種依存文字と外字)

そのコード範囲は機種依存文字ばかりで外字は含まれていません.
ユーザ定義外字は95~114区 (0xF040~0xF9FC) です.

Mac ユーザも対象に含めるならば,9~14区 (0x8540~0x889E) も
機種依存文字です.

余計なお世話かもしれませんが,上記の範囲に限らず,シフト JIS の
コード範囲のうち JIS X 0208 で未定義の部分はすべて禁止にした方が
いいんじゃないでしょうか?

・JIS X 0208 で未定義の範囲 (主なものだけ)
9~15区 (0x8540 ~ 0x889E)
85~120区 (0xEB40 ~ 0xFCFC)


Shift_JIS
http://ja.wikipedia.org/wiki/Shift_JIS

Microsoftコードページ932 (Windows版シフトJIS)
http://ja.wikipedia.org/wiki/Microsoft%E3%82%B3% …

MacJapanese (Mac版シフトJIS)
http://ja.wikipedia.org/wiki/MacJapanese
    • good
    • 0
この回答へのお礼

if((0xFA40 <= targetChar) && ((targetChar <= 0xEC4B)) {

if((0xFA40 <= targetChar) && (targetChar <= 0xfC4B)) {
にして、少しの手直しでやりたかった処理になりました。
ありがとうございました。

機種依存文字にも種類がたくさんあることを知りました。
外字とは違うのですね。
現在はWINDOWSでの入力が前提だったためにマックなどは対象にしていませんが今後はわからないので確かに考慮しなければならないと思います。
文字コードは奥が深そうなので、今後もっと勉強しないといけないと思いました。
本当にありがとうございました。

お礼日時:2007/06/12 11:25

> targetChar = (char) (charByte * 0x100 + charArray[i + 1]);


> の行も直さないとダメなようなのですがどこか参考になるサイトなどはないでしょうか?

SJISコードってビッグエンディアンだっけ? リトルエンディアンなら
< targetChar = (char) (charByte + 0x100 * charArray[i + 1]);
では?
そうでないならかけ算の代わりにシフト演算子を使うと良いかも。

なお、参考になりそうなサイトは知りませんので悪しからず。
    • good
    • 0
この回答へのお礼

3番目の回答のシフト演算子を使う方法で解決できました。
ビックエンディアンとリトルエンディアンという用語がわからないので調べてみます。
ありがとうございました。

お礼日時:2007/06/12 11:19

> if (charByte >= 128) {


この行が間違い。
まず、Javaの整数型は符号付だから
< if (charByte < 0) {
とすべきだけど、それでも判定が逆だね。ここは
< if (charByte >= 0) {
と直したら正しくなるか。

現状だと、全てのバイトについてelseの側に行って、最後のバイトではその次にもアクセスするのでava.lang.ArrayIndexOutOfBoundsExceptionになる。
    • good
    • 0
この回答へのお礼

回答ありがとうございます。
書いてある通りに
if (charByte >= 0) {
に直してみたのですがたとえば'あ'という文字の処理では
-126と-96のbyte[2]が取れていて思うような動作にはなりませんでした。
条件だけでなく、
targetChar = (char) (charByte * 0x100 + charArray[i + 1]);
の行も直さないとダメなようなのですがどこか参考になるサイトなどはないでしょうか?
すみませんがよろしくお願いします。

お礼日時:2007/06/11 17:40

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!