エンコード時の文字コードが不明なURLをJavaでデコード

javaでURLのデコードを行う場合は一般的にはコレ

URLDecoder.decode(url, “文字コード”)

システムでURLエンコードを行うのであれば一般的には

文字コードにおいてはUTF-8を使用する事になるんだけど、

この文字コードが分からないケースってのに今回ぶち当たった。

と、いうのは、仕事でアクセスログの解析をやってて、

リファラのURLをデコードする必要が出てきた。

でも、よく考えたらリファラURLに含まれるエンコード文字列なんてのは

<meta http-equiv=”content-type” content=”text/html; charset=UTF-8″ />

なんて感じでcharsetで指定された文字コードでエンコードされる訳で、

サイトによって異なる訳だ。

つまりSJISだったりEUC-JPだったりUTF-8だったりと、何の文字コードで

エンコードされたURLなのかは、そのサイト自信しか知らない事になる。

と、いう事で愚直に

URLDecoder.decode(url, “UTF-8”)

なんてソースを書いてたら見事にデコード後の文字列が文字化けした訳だorz

と、いう事で、文字コード判定を行わなければならない事に気付いた。

で、文字コードを判定してくれるライブラリを探した。

http://code.google.com/p/juniversalchardet

Mozillaの内部で使用されていたロジックをjavaに移植したものらしい。

で、このライブラリを組み込んで、URLデコード処理は、最終的にこんな感じになった。

public static String decodeUrl(String url) throws UnsupportedEncodingException {

if (StringUtils.isBlank(url)) return url;

byte[] b = URLDecoder.decode(url, “iso-8859-1”).getBytes(“iso-8859-1”);

UniversalDetector detector = new UniversalDetector(null);

detector.handleData(b, 0, b.length);

detector.dataEnd();

String enc = detector.getDetectedCharset();

if (enc == null) {

return url;

}

detector.reset();

return new String(b, enc);

}

とりあえず、色々なサイトのエンコード済みURLを

こいつでデコードしてみたけど、

うまい事デコードされるようになった。

いやぁ、一安心


2010/04/15 追記。上記じゃ全然ダメでしたw


何がダメかというと、juniversalchardet。

デコード時の文字コードがEUC-JPだった場合に、判定に失敗する可能性が非常に高い。

EUC-JPの判定は難しいとは耳にした事はあったけど…

で、またまた色々と調査。

で、よく考えたら文字コード名なんて必要ない訳で「正しく文字列が構築できたか」が問題な事に気付いた。

まぁ、そうだよね。

で、見つけたのがnioパッケージの

CharsetDecoder

こいつのdecodeメソッドは文字がマッピングできなかった場合に

CharacterCodingExceptionを投げてくれるナイスな奴だ。

まぁ、URLエンコードで使用されている文字コードっていったら

だいたい

ISO-2022-JP

EUC-JP

UTF-8

windows-31j

に限定されてくるので、今回はこれらの文字コードに該当する

CharsetDecoderを生成し、文字列の構築を試行するようにしてみた。

/** URLデコードに使用する文字コード */

private static List<Charset> decodeCharsets;

static {

decodeCharsets = new ArrayList<Charset>();

decodeCharsets.add(Charset.forName(“ISO-2022-JP”));

decodeCharsets.add(Charset.forName(“EUC-JP”));

decodeCharsets.add(Charset.forName(“UTF-8”));

decodeCharsets.add(Charset.forName(“windows-31j”));

}

/**

* URLのデコードを行う

* @param url

* @return

* @throws UnsupportedEncodingException

*/

public static String decodeUrl(String url) throws UnsupportedEncodingException {

if (url == null || url.trim().equals(“”)) return url;

// ISO-8859-1でデコードしバイトを取得

byte[] b = null;

try {

b = URLDecoder.decode(url, “iso-8859-1”).getBytes(“iso-8859-1”);

} catch (IllegalArgumentException e) {

// %の形式不正などの場合

// ※ エラー時の処理

}

// それぞれの文字コードで文字列構築を試行する

for (Charset charset : decodeCharsets) {

CharsetDecoder decoder = charset.newDecoder();

try {

return decoder.decode(ByteBuffer.wrap(b)).toString();

} catch (CharacterCodingException e) {

continue;

}

}

return new String(b);

}

こんな感じにしてみたら、URLデコード時の文字化けがすっかり解消された。

いやぁ、一安心。(今度こそw)

Comments are closed.