トップ 一覧 ping 検索 ヘルプ RSS ログイン

Javaでの文字コードの扱いの変更点

  • 追加された行はこのように表示されます。
  • 削除された行はこのように表示されます。
!!!Javaでの文字コードの扱い
[Java]{{category 文字化け}}

なんだかんだといつも厄介な文字コードの変換についてのメモ

結局、ファイル読込み、文字列変数の取り扱い、ファイル書き込みなどの各局面で、実際はどの文字コードが使用されているかを考え、適切にコンバートすることが肝要

*[インターネットの言葉と技術|http://www.kanzaki.com/netfan/]
*[Javaでの文字コードの扱い|https://www.typea.info/tips_/index.php/Java%E3%81%A7%E3%81%AE%E6%96%87%E5%AD%97%E3%82%B3%E3%83%BC%E3%83%89%E3%81%AE%E6%89%B1%E3%81%84#Java.E3.81.A7.E3.81.AE.E6.96.87.E5.AD.97.E3.82.B3.E3.83.BC.E3.83.89.E3.81.AE.E6.89.B1.E3.81.84]

!!Javaに限らず、厄介な文字化けについて
{{category 文字化け}}

{{amazon 477414164X}}
{{amazon 481633243X}}
!!基本事項

!Stringクラス
::仕様では、[String クラス|http://www.y-adagio.com/public/standards/tr_javalang2/typesValues.doc.html#26992]はUnicode文字の並びを表す

*String クラスのソースコード(%JAVA_HOME%/src.zip)を見ると、Unicode文字の並びをchar型の配列として保持している。
*[char型|http://www.y-adagio.com/public/standards/tr_javalang2/typesValues.doc.html#48440]は、[Unicode|http://e-words.jp/w/Unicode.html]文字を表す16ビット符号無し整数で、'\u0000'〜'\uffff' すなわち 0〜65535を表現できる
*Javaで扱うUnicodeは、1文字を16ビット(2バイト)[UCS-2|http://e-words.jp/w/UCS-2.html]である。
*現在はUnicode全体は4バイトで定義([UCS-4|http://e-words.jp/w/UCS-4.html])されている。 

!ソースコードの変換
::ソースコードのコンパイル時、プラットフォームの文字コードやファイルの文字コードに依存してしまう。

*Windowsでソースを書いてLinuxでコンパイルを行ったりするような場合には、プラットフォームとソースコードの文字コードの不一致によって文字化けが発生する。
*[native2ascii|http://java.sun.com/j2se/1.5.0/ja/docs/ja/tooldocs/windows/native2ascii.html] を使用して、ソースコードに含まれるUnicode以外の文字を、[Unicodeエスケープ|http://www.y-adagio.com/public/standards/tr_javalang2/lexical.doc.html#100850]に変換する。

::プロパティファイルの変換
*プロパティファイル等、Java プログラムで利用するファイルも、ソースコード同様、[native2ascii|http://java.sun.com/j2se/1.5.0/ja/docs/ja/tooldocs/windows/native2ascii.html] を使用して文字コードを変換する。

!!ファイルの読み書き
プログラムの実行時にファイルを読込む必要がある場合等は、ファイルに合わせた文字コードでファイルを読まなければ文字化けしてしまう場合がある。
!文字コードを指定してファイルを読む
::FileInputStream を利用することにより、文字コードを指定してファイルを読むことができる
 BufferedReader reader  
   = new BufferedReader(new InputStreamReader(new FileInputStream("/var/files/ebicdic.txt"),"Cp943c"));
!文字コードを指定してファイルを書く
::FileInputStream を利用することにより、文字コードを指定してファイルを書くことができる
 BufferedWriter writer 
    = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("c:\\shift_jis.txt"), "MS932"))

!!文字コードの変換
"Unicodeで定義された文字集合で表現された文字列" から "バイト列" へのエンコード方法、逆にデコード方法を指定する。

!エンコード
::エンコード方式(文字セット)を指定して、Stringからバイト列を取得する
 byte[] String.getBytes(String charsetName)
*java.lang.StringCoding.encode(String charsetName, char[] value ...)
*sun.io.CharToByteConverter

!デコード
::デコード方式(文字セット)を指定して、バイト列からStringを生成する
 new String(byte[] bytes, String charsetName)
*java.lang.StringCoding.decode(String charsetName, byte[] bytes ...)
*sun.io.ByteToCharConverter

!文字コードの変換
::上記を使用して、文字コードを変換する
 String newCode = new String(oldCode.getBytes("Cp930"), "MS932");

!デフォルトエンコード(デコード)
::エンコード(デコード)方式を指定しないと、プラットフォームのデフォルトエンコーディングが使用される。

システムプロパティ
,名前,説明,例
,file.encoding,デフォルトのコード系,MS932
,file.encoding.pkg,コード系を取り扱うパッケージ,sun.io
,line.separator,行のセパレータ,CRLF
*System.getProperty("file.encoding")
*sun.io.Converters.getDefaultEncodingName()

!文字コードの16進ダンプ
::デバッグ用
  public static String stringDump(String s) {
    if (s == null) return "";
    StringBuffer buf = new StringBuffer();
    char[] c = s.toCharArray();
    for (int i=0; i<c.length; i++) {
      buf.append(Integer.toString((int)c[i], 16) + " ");
    }
    return buf.toString();
  }
!文字コードの16進ダンプを復元
::デバッグ用
  public static String decodeDumpString(String s) {
    StringBuffer result = new StringBuffer();
    StringTokenizer tok = new StringTokenizer(s.trim(), " "); 
    
    List lst = new ArrayList();
    while(tok.hasMoreTokens()) {
      lst.add(new Character((char)Integer.parseInt(tok.nextToken(),16)));
    }
    char[] buf = new char[lst.size()];
    for (int i=0; i<lst.size(); i++) {
      buf[i] = ((Character)lst.get(i)).charValue();
    }
    return (new String(buf));
  }

!エンコーディング
*文字コード
*[Microsoftコードページ932|http://ja.wikipedia.org/wiki/Microsoft%E3%82%B3%E3%83%BC%E3%83%89%E3%83%9A%E3%83%BC%E3%82%B8932]
*[Unicode|http://ja.wikipedia.org/wiki/Unicode]

::Javaでサポートされるエンコーディング
*[1.3|http://java.sun.com/j2se/1.3/docs/guide/intl/encoding.doc.html]([日本語|http://java.sun.com/j2se/1.3/ja/docs/ja/guide/intl/encoding.doc.html])
*[1.4|http://java.sun.com/j2se/1.4/docs/guide/intl/encoding.doc.html]([日本語|http://java.sun.com/j2se/1.4/ja/docs/ja/guide/intl/encoding.doc.html])
*[1.5|http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html]([日本語|http://java.sun.com/j2se/1.5.0/ja/docs/ja/guide/intl/encoding.doc.html])

::エンコーディングの別名一覧
*[sun.io.CharacterEncoding|http://www2s.biglobe.ne.jp/~katsum/java/encoding.html]

::その他
*MS932またはSJISの別名として定義されており、どちらの別名となるかはバージョンに依存している(JDK 1.3ではMS932だが、JDK 1.4ではSJISとなる)。
*http://www.atmarkit.co.jp/fjava/rensai2/webopt08/webopt08.html

::CP943cとShift_JISの文字コードの違いについて
*http://www-1.ibm.com/support/docview.wss?uid=std3b32aea767378855449256f010028e2f4

!!マルチパートのエンコード
!ファイルアップロードの場合にファイル名が文字化けする
::Form
 <form id="formUpload" action="upload.html" method="POST" enctype="multipart/form-data" >
   <input name="attach_file" />
   <input type="submit" value="アップロード"/>
 </form>

::文字コードをiso-8859-1として変換
*http://ja.wikipedia.org/wiki/ISO/IEC_8859-1
*Spring の場合

 @RequestMapping(value="/upload.html", method = RequestMethod.POST)
 public String uploadFile(MultipartFile file) {
     String filename = new String(file.getOriginalFilename().getBytes("iso-8859-1"),"utf-8");
                 :

!ファイルダウンロード時にファイル名が文字化けする
 //String fileName = new String(originalFileName.getBytes("utf-8"),"iso-8859-1"); // Chrome OK, IE NG
 String fileName = new String(originalFileName.getBytes("ms932"),"iso-8859-1"); // Chrome OK, IE OK
 
 response.setHeader("Content-Type", "application/octet-stream");
 response.setHeader("Content-Disposition", "filename=\"" + fileName + "\"");
 
!!Shift_JISの取り扱い

*MS932またはSJISの別名として定義されており、どちらの別名となるかはバージョンに依存している(JDK 1.3ではMS932だが、JDK 1.4ではSJISとなる)。
*機種依存文字(NEC特殊文字、NEC選定IBM拡張文字、IBM拡張文字)や〜‖−¢£¬などの扱いが異なり、誤って使用すると“?”に文字化け

*http://www.atmarkit.co.jp/fjava/rensai2/webopt08/webopt08.html

*文字コード 参照

::円記号
*Shift_JISでは、半角円記号とバックスラッシュを区別しないが、する文字コード体系だと見た目上は、半角円記号なのに、Stringのメソッドが正しく動作しない(ように見える)
 String str1 = "\u005c\u005c";
 String str2 = "\u00a5";
 System.out.println(str1 + " = " + str2);
 System.out.println(str1.equals(str2));

 \ = \
 false
!!ファイルの文字コードを判別する
*[[ファイルの文字コードを判別する|Java ファイルの文字コードを判別する]]
!!その他
{{amazon 4774107808}}
!Webアプリケーションの文字化け対策
*Filterで文字化け対策
*文字化けの対処
----
{{amazon 4822282775}}
Java5.0でだいぶ機能追加があったけれど、丁寧に説明してくれてます。
試験対策でなくても非常に有用

{{amazon 482228168X}}
ただ、試験範囲から外れちゃったところも多いので、こちらの本もあわせて読んでおくとよいかも(もったいないか?)
{{include_html banner_html, "!amazon_promotion2"}}

!!その他文字化けについて
{{category 文字化け}}
*Excel VBA 文字列をバイト配列に変換
*Filterで文字化け対策
*HTML javascript:を利用するとデコードされる
*J2EE Tips
*Java ファイルの文字コードを判別する
*Javaでの文字コードの扱い
*Linux バックスペースが文字化けしてしまう
*Python URLエンコード
*Python UnicodeEncodeError の対処
*Python ファイルの文字コード
*SQL Plus
*WAS から Java Mail送信で文字化け
*vi
*画面に入力された文字コードを調べる
*文字コード
*文字化けの対処

{{include_html redirect_html, "!JAVA_CHAR_CODE"}}