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.