Java の URLEncoder / URLDecoder で文字化けする問題
最近、バタバタしていてあまり記事を投稿できていませんでしたが久し振りの投稿です。
CGIでURLエンコードした文字列をJavaでURLデコードするとなぜか日本語の一部が文字化けする問題が発生していました。色々と調べていると、Perlでは2バイトコードかどうかに関係なく、1バイトずつ文字列をURLエンコードするのに対し、Javaは2バイトコードのみをURLエンコードしていることが分かりました。
ただ、どちらが間違いという事は無く、両方ともエンコーダーの実装としては正しいみたいです。ただし、Javaのデコーダーの実装が良くないみたいで、PerlでURLエンコードした文字列を正確に文字列に戻せない不具合があるようです。
しょうがないので、以下のように自前で正常に動作するURLDecoderを作成しました。
package com.tezukaosamumagazineclub.invoice.epsilon;
import java.io.UnsupportedEncodingException;
public class URLDecoder {
public static String decode(String s, String enc) throws UnsupportedEncodingException {
boolean needToChange = false;
int numChars = s.length();
StringBuffer sb = new StringBuffer(numChars > 500 ? numChars / 2 : numChars);
int i = 0;
if (enc.length() == 0) {
throw new UnsupportedEncodingException("URLDecoder: empty string enc parameter");
}
char c;
byte[] bytes = null;
while (i < numChars) {
c = s.charAt(i);
switch (c) {
case '+':
sb.append(' ');
i++;
needToChange = true;
break;
case '%':
try {
if (bytes == null) {
bytes = new byte[numChars - i];
}
int pos = 0;
while ((i + 2) < numChars) {
if (c == '%') {
bytes[pos++] = (byte) Integer.parseInt(s.substring(i + 1, i + 3), 16);
i += 3;
} else {
bytes[pos++] = (byte) Integer.parseInt(
Integer.toHexString(s.charAt(i)), 16);
i++;
}
if (i < numChars)
c = s.charAt(i);
}
if ((i < numChars) && (c == '%')) {
throw new IllegalArgumentException(
"URLDecoder: Incomplete trailing escape (%) pattern");
}
sb.append(new String(bytes, 0, pos, enc));
} catch (NumberFormatException e) {
throw new IllegalArgumentException(
"URLDecoder: Illegal hex characters in escape (%) pattern - "
+ e.getMessage());
}
needToChange = true;
break;
default:
sb.append(c);
i++;
break;
}
}
return (needToChange ? sb.toString() : s);
}
}



読ませて頂きました。
>URLDecoder で文字化けする問題
私もこの問題に悩まされていたので、本当に助かりました。
ありがとうございました。
rdera
31 10月 08 at 17:04:57
自分が悩んだ問題はなるべくブログに書くようにしてますので、Javaに関係する方ならRSS登録をオススメします!(笑)
また、遊びに来て下さい。
daisuke
13 11月 08 at 11:55:30
とても参考になりました。
“%83N” のパターンに対応していないようですね。
sb.append(new .. の部分を
if (i < numChars)
bytes[pos++] = (byte)s.charAt(i++);
sb.append(new String(bytes, 0, pos, enc));
とすることで対応出来るようです。
匿名
26 8月 10 at 15:34:21