13F

備忘録

Javaでメールを送るときのエンコーディング

2007-10-11 01:40:26 | Weblog
Javaでメールを送るときなどに、ふつうのISO-2022-JP でエンコードすると丸付き数字とか、草ナギ剛の「なぎ」とかが文字化けしたりする。

これの暫定対策として、JDK 5.0 update7 から、CP50220 などのエンコーディングが追加されていて、これを使うとそういった文字も文字化けしなくなる。
http://www.yks.ne.jp/~tsurucha/ChangeLog/2007-03.html#2007-03-22

ってとこまでは聞いたことがあったんだけど、全角ダッシュ(uFF0D)とかポンド記号(uFFE1)みたいな、今まで手動で代わりの文字(u2212とか)に変換して対処していたようなものも、このエンコーディングだとそのままOKになるようだ。これは知らなかった。

以下、ちょっとした確認。
import java.io.*;
import java.nio.*;
import java.nio.charset.*;

public class EncodeChecker {
  public static void main(String[] args) throws Exception {
    // 怪しげな文字。以下からいただきました。
    // http://www.ingrid.org/java/i18n/encoding/ja-conv.html
    char[] chars = {
      '\\', '\u007E', '\u00A2', '\u00A3', '\u00AC',
      '\u00A5', '\u203E', '\u2014', '\u2015', '\u2016',
      '\u2026', '\u2212', '\u2225', '\u301C', '\u22EF',
      '\uFF0D', '\uFF5E', '\uFFE0', '\uFFE1', '\uFFE2',
      '\uFFE3',
      '\u2160', '\u2468', '\u3231', '\u3336', '\u5F45',
    };
    
    PrintWriter writer = new PrintWriter(new File("result.txt"), "UTF-8");
    checkAll(writer, "ISO-2022-JP", chars);
    writer.println();
    checkAll(writer, "CP50220", chars);
    writer.close();
  }

  private static void checkAll(PrintWriter writer, String encoding, char[] target)
  throws UnsupportedEncodingException {
    EncodeChecker checker = new EncodeChecker(encoding);
    writer.println(String.format("# %s", encoding));
    for (char c : target) {
      writer.write(checker.check(c));
      writer.println();
    }
  }

  private CharsetEncoder encoder;

  public EncodeChecker(String encoding)
  throws UnsupportedEncodingException {
    Charset charset = Charset.forName(encoding);
    encoder = charset.newEncoder()
      .onMalformedInput(CodingErrorAction.REPORT)
      .onUnmappableCharacter(CodingErrorAction.REPORT);
  }

  public String check(char c) {
    StringBuilder result = new StringBuilder();
    result.append(String.format("\\u%04X [%c] : ", (int)c, c));

    CharBuffer cb = CharBuffer.wrap(new char[]{c});
    ByteBuffer bb = ByteBuffer.allocate(10);
    CoderResult cr = encoder.encode(cb, bb, true);

    if (cr.isUnderflow()) {
      result.append("○ [ ");
      int len = bb.position();
      for (int i=0; i<len; i++) {
        result.append(String.format("%02X ", bb.get(i)));
      }
      result.append("]");
    } else if (cr.isError()) {
      result.append("×");
    } else {
      result.append("?");
    }

    return result.toString();
  }
}

1.5.0_13-b05 で実行したときのresult.txtの中身。
# ISO-2022-JP
u005C [\] : ○ [ 5C ]
u007E [~] : ○ [ 7E ]
u00A2 [¢] : ○ [ 1B 24 42 21 71 ]
u00A3 [£] : ○ [ 21 72 ]
u00AC [¬] : ○ [ 22 4C ]
u00A5 [] : ○ [ 1B 28 4A 5C ]
u203E [~] : ○ [ 7E ]
u2014 [―] : ○ [ 1B 24 42 21 3D ]
u2015 [―] : ×
u2016 [∥] : ○ [ 21 42 ]
u2026 […] : ○ [ 21 44 ]
u2212 [-] : ○ [ 21 5D ]
u2225 [∥] : ×
u301C [~] : ○ [ 21 41 ]
u22EF […] : ×
uFF0D [-] : ×
uFF5E [~] : ×
uFFE0 [¢] : ×
uFFE1 [£] : ×
uFFE2 [¬] : ×
uFFE3 [ ̄] : ○ [ 21 31 ]
u2160 [Ⅰ] : ×
u2468 [⑨] : ×
u3231 [㈱] : ×
u3336 [㌶] : ×
u5F45 [] : ×

# CP50220
u005C [\] : ○ [ 5C ]
u007E [~] : ○ [ 7E ]
u00A2 [¢] : ○ [ 1B 24 42 21 71 ]
u00A3 [£] : ○ [ 21 72 ]
u00AC [¬] : ○ [ 22 4C ]
u00A5 [] : ○ [ 1B 28 4A 5C ]
u203E [~] : ○ [ 7E ]
u2014 [―] : ×
u2015 [―] : ○ [ 1B 24 42 21 3D ]
u2016 [∥] : ○ [ 21 42 ]
u2026 […] : ○ [ 21 44 ]
u2212 [-] : ○ [ 21 5D ]
u2225 [∥] : ○ [ 21 42 ]
u301C [~] : ○ [ 21 41 ]
u22EF […] : ×
uFF0D [-] : ○ [ 21 5D ]
uFF5E [~] : ○ [ 1B 24 28 44 22 37 ]
uFFE0 [¢] : ○ [ 1B 24 42 21 71 ]
uFFE1 [£] : ○ [ 21 72 ]
uFFE2 [¬] : ○ [ 22 4C ]
uFFE3 [ ̄] : ○ [ 21 31 ]
u2160 [Ⅰ] : ○ [ 2D 35 ]
u2468 [⑨] : ○ [ 2D 29 ]
u3231 [㈱] : ○ [ 2D 6A ]
u3336 [㌶] : ○ [ 2D 47 ]
u5F45 [] : ○ [ 1B 24 28 44 3C 74 ]

gooブログってEUCなのか…。