J2ME 無 java.net.URLEncoder,需自行實作 application/x-www-form-urlencoded 編碼,以便向伺服器傳送中文參數。
String data = "param=" + URLEncoder.encode("中文參數");
outputStream.write(data.getBytes());
// 伺服端 (Servlet): request.getParameter("param") 即得 "中文參數"
package com.j2medev.httpme.tools;
import java.io.*;
public class URLEncoder {
private static boolean[] dontNeedEncoding;
private static String defaultEncName;
static final int CASE_DIFF = 'a' - 'A';
static {
dontNeedEncoding = new boolean[256];
for (int i = 'a'; i <= 'z'; i++) dontNeedEncoding[i] = true;
for (int i = 'A'; i <= 'Z'; i++) dontNeedEncoding[i] = true;
for (int i = '0'; i <= '9'; i++) dontNeedEncoding[i] = true;
dontNeedEncoding[' '] = true; // 空格稍後轉 '+'
dontNeedEncoding['-'] = true;
dontNeedEncoding['_'] = true;
dontNeedEncoding['.'] = true;
dontNeedEncoding['*'] = true;
defaultEncName = System.getProperty("microedition.encoding");
if (defaultEncName == null || defaultEncName.trim().length() == 0) {
defaultEncName = "UTF-8";
}
}
private URLEncoder() {}
public static String encode(String s) {
return encode(s, defaultEncName);
}
public static String encode(String s, String enc) {
StringBuffer out = new StringBuffer(s.length());
ByteArrayOutputStream buf = new ByteArrayOutputStream();
OutputStreamWriter writer = null;
try { writer = new OutputStreamWriter(buf, enc); }
catch (UnsupportedEncodingException e) {
try { writer = new OutputStreamWriter(buf, defaultEncName); }
catch (UnsupportedEncodingException ignored) {}
}
boolean needToChange = false;
boolean wroteUnencoded = false;
for (int i = 0; i < s.length(); i++) {
int c = s.charAt(i);
if (c < 256 && dontNeedEncoding[c]) {
if (c == ' ') { c = '+'; needToChange = true; }
out.append((char) c);
wroteUnencoded = true;
} else {
// 需編碼字元
try {
if (wroteUnencoded) {
writer = new OutputStreamWriter(buf, enc);
wroteUnencoded = false;
}
if (writer != null) writer.write(c);
// 處理 Surrogate Pair
if (c >= 0xD800 && c <= 0xDBFF && i + 1 < s.length()) {
int d = s.charAt(i + 1);
if (d >= 0xDC00 && d <= 0xDFFF) {
writer.write(d);
i++;
}
}
writer.flush();
} catch (IOException e) {
buf.reset(); continue;
}
byte[] ba = buf.toByteArray();
for (byte b : ba) {
out.append('%');
char ch = forDigit((b >> 4) & 0xF, 16);
if (isLetter(ch)) ch -= CASE_DIFF;
out.append(ch);
ch = forDigit(b & 0xF, 16);
if (isLetter(ch)) ch -= CASE_DIFF;
out.append(ch);
}
buf.reset();
needToChange = true;
}
}
return needToChange ? out.toString() : s;
}
private static boolean isLetter(char c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
}
private static char forDigit(int digit, int radix) {
if (digit < 0 || digit >= radix) return '\0';
if (radix < 2 || radix > 36) return '\0';
return (char) (digit < 10 ? '0' + digit : 'a' - 10 + digit);
}
}
已於多款手機 (Nokia, Sony Ericsson, Motorola) 實測通過,正確編碼中文並被伺服端 (Servlet/PHP/ASP.NET) 正確解碼。