プロが教える店舗&オフィスのセキュリティ対策術

 今、客先のデータをJavaで処理しようとしているのですが、そのデータ(Shift-JISの文字列データ)には、今まで使われてきた「外字」が含まれています。
 私の知っている範囲では、Shift-JISの文字列でも、Javaで読み込んだら内部的にUnicodeに変換されるのではないかと思っているのですが(←間違っているかもしれません)、そのUnicode変換の際に外字の部分はどうなってしまうのでしょうか。また、Unicodeに変換された文字列を、出力の際にまたShift-JISに戻すことになると思うのですが、そのときにはちゃんと以前の外字コードに戻ってくれることが保証されているのでしょうか。
 JavaのリファレンスでStringクラスのページで「外字」という文字列で検索してみたのですが、まったくひっかからなかったので不安になっています。
 よろしくお願い致します。

A 回答 (2件)

 #1です。



 似たような質問があがっているところを見つけました。

http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.ph …

 ということで、これを参考に実験です。

 UTF-16の外字の領域を一文字ずつShift-JISに変換して、また、UTF-16に戻して、ちゃんともとにもどるか、やってみました。

public class Gaiji {
  public static void main(String[] args) throws Exception {
    final String charSet = "Shift-JIS";
    
    boolean allEqual = true;
    
    for (char c = 0xE000; c <= 0xF8FF; c++) {
      System.out.print(Integer.toHexString((int)c) + "→");
      char[] carray = {c};
      String source = new String(carray);
      byte[] sjis = source.getBytes(charSet);
      
      for (byte b : sjis)
        System.out.print(Integer.toHexString(((int)b & 0xFF)));
      
      System.out.print("→");
      
      String result = new String(sjis, charSet);
      System.out.print(Integer.toHexString((int)result.charAt(0)) + " : ");
      
      boolean equal = source.equals(result);
      System.out.println(equal);
      
      allEqual = (allEqual && equal);
    }
    System.out.println();
    System.out.println("すべて一致 : " + Boolean.toString(allEqual));
  }
}
(コンパイルするときは全角スペースを半角スペースに変換してからにしてください)

 ところがぜんぜんダメ。
 元に戻りません。
 ということで、Windowsの本来の文字コードWindows-31Jでやってみました。

final String charSet = "Windows-31J"; ←変更

 どうやらうまく行っているのですが、途中までは順調に変換され、元に戻るものの、途中からだめになりました。
 どうやら、UTF-16 : E757 Shift-JIS : F9FC の次からだめになっています。

 外字エディタで見てみるとちょうどF9FCまでが、Shift-JISの外字領域のようです。
 つまり、UTF-16のほうがShift-JISより、外字領域が大きいみたいです。
 当然そこから先は、Shift-JISには、変換不能ということになります。

 というわけで、

1.Windowsでは、通常ならCharSetがShift-JISでも大体大丈夫だけど、外字の変換をするときにはちゃんとWindows-31Jを指定しないとダメ。

2.UTF-16 : E000~E757 Shift-JIS : F040~F9FC の範囲なら変換可能。
 UTF-16 : E758~F8FF の範囲はShift-JISに相手がいないので無理。

 ってことで、Shift-JISで外字が設定されているのなら、大丈夫ってことになるんじゃないでしょうか。

参考URL:http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.ph …
    • good
    • 1
この回答へのお礼

ありがとうございます!
概念としても理解できましたし、扱うためのコーディング例までわかりました。本当にありがとうございました。

お礼日時:2005/10/05 19:27

 こんばんは、興味があったので実験してみました。


(環境 WindowsXP SP2 : JDK 1.5.0_04)

 外字エディタにて シフトJISで F040 Unicodeで E000 に外字を作成。(手書きのふにゃふにゃ温泉マーク)

char[] c = {0xE000};
String s = new String(c);
System.out.println(s);

 これで、ちゃんと外字が出てきました。

 次に、メモ帳にて外字の温泉マークが書いてあるテキストをシフトJISで保存。

BufferedReader br = new BufferedReader(new FileReader("gaiji.txt"));
for (String line; (line = br.readLine()) != null;) {
  System.out.println(line);
}

 やっぱり、普通に温泉マークが出てきました。

 今度は、外字エディタで作った温泉マークを削除。
 さっきのコードを実行すると、温泉マークが出てこず、空白になります。

 早い話が、char型変数やStringクラスが扱っているのは文字コードという純然たる数字であって、実際にフォントとして描くのはシステムに依存しているって事なんじゃないでしょうか。
 つまり、結局のところ、OSでその文字コードに外字が割り当ててあれば、ちゃんと表示され、されていなければ、それなりになるって事だと思います。

この回答への補足

ありがとうございます。
これは
・Shift-JISでは外字領域はF040以降(←これは知ってました)
・UnicodeではE000以降
・それらは1対1で対応している
 ・たとえばF040<->E000、F041<->E001、というように
・これをやってくれるのは、Javaの仕様

っていうことなんでしょうか。
 Unicodeに直した後は、画面には表示する予定はないので、フォントの割り当てなどは気にならないのですが、Shift-JIS変換の際に相互の可逆性があるかどうかが気になっているのです。
 ご存じでしたら教えてください。お願いします。<(_ _)>

補足日時:2005/10/04 11:34
    • good
    • 0

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