エンコード時の文字コードが不明な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)

Check

コメントをどうぞ

メールアドレスが公開されることはありません。


次のHTML タグと属性が使えます: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

管理人運営サイト
<技術情報サイト:PGBox>
PGBOX