Java 原始碼中可使用 \uXXXX 表示 Unicode 字符(XXXX 為 4 位十六進制)。編譯器在**詞法分析階段**即解析轉義,故 "\u0022" 等同於 "\"",甚至可寫 public static void main\u0028String[] args\u0029(極不推薦)。
public static String toUnicodeEscape(String str) {
if (str == null) return null;
StringBuilder sb = new StringBuilder(str.length() * 6); // 預估容量
for (char c : str.toCharArray()) {
if (c <= 0xFFFF) { // BMP 字符
sb.append(String.format("\\u%04x", (int) c));
} else { // 補充字符平面 (需代理對)
sb.append(String.format("\\u%04x\\u%04x",
(int) Character.highSurrogate(c),
(int) Character.lowSurrogate(c)));
}
}
return sb.toString();
}
// 測試
System.out.println(toUnicodeEscape("簡介")); // \u7b80\u4ecb
public static String fromUnicodeEscape(String escaped) {
if (escaped == null) return null;
StringBuilder sb = new StringBuilder(escaped.length());
for (int i = 0; i < escaped.length(); ) {
char c = escaped.charAt(i++);
if (c == '\\' && i < escaped.length() && escaped.charAt(i) == 'u') {
i++; // 跳過 'u'
if (i + 4 <= escaped.length()) {
String hex = escaped.substring(i, i + 4);
try {
int codePoint = Integer.parseInt(hex, 16);
sb.append((char) codePoint);
i += 4;
continue;
} catch (NumberFormatException ignored) {
// 非法十六進制,按原樣輸出
}
}
}
sb.append(c);
}
return sb.toString();
}
// 測試
System.out.println(fromUnicodeEscape("\\u7b80\\u4ecb")); // 簡介
public class UnicodeUtil {
// 字符串 -> \uXXXX 轉義
public static String escape(String str) { ... } // 同 toUnicodeEscape
// \uXXXX 轉義 -> 字符串(支援 \t \n \r \f \\ \' \" \uXXXX)
public static String unescape(String escaped) {
if (escaped == null) return null;
StringBuilder sb = new StringBuilder(escaped.length());
for (int i = 0; i < escaped.length(); ) {
char c = escaped.charAt(i++);
if (c == '\\' && i < escaped.length()) {
c = escaped.charAt(i++);
switch (c) {
case 'u': // Unicode
if (i + 4 <= escaped.length()) {
int val = 0;
for (int j = 0; j < 4; j++) {
char h = escaped.charAt(i++);
val = (val << 4) + hexValue(h);
}
sb.append((char) val);
} else sb.append("\\u");
break;
case 't': sb.append('\t'); break;
case 'n': sb.append('\n'); break;
case 'r': sb.append('\r'); break;
case 'f': sb.append('\f'); break;
case '\\': sb.append('\\'); break;
case '\'': sb.append('\''); break;
case '"': sb.append('"'); break;
default: sb.append('\\').append(c);
}
} else {
sb.append(c);
}
}
return sb.toString();
}
private static int hexValue(char c) {
if (c >= '0' && c <= '9') return c - '0';
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
throw new IllegalArgumentException("Invalid hex: " + c);
}
}
// 1. Properties 存儲自動轉義(ISO-8859-1 編碼)
Properties props = new Properties();
props.setProperty("key", "中文");
props.store(new FileOutputStream("config.properties"), null);
// 文件內容:key=\u4e2d\u6587
// 讀取自動解析
props.load(new FileInputStream("config.properties"));
System.out.println(props.getProperty("key")); // 中文
// 2. Apache Commons Text (推薦生產)
StringEscapeUtils.escapeJava("中文") // \u4e2d\u6587
StringEscapeUtils.unescapeJava("\\u4e2d\\u6587") // 中文
\uD83D\uDE00,單個 char 無法容納,Java 內部用 int (code point) 處理。javac -encoding UTF-8`,運行時 `java -Dfile.encoding=UTF-8`。StringBuilder 容量,避免擴容拷貝。Unicode 轉義 (\uXXXX) 是 Java 處理非 ASCII 字符的基礎機制。手動實現轉換器有助於理解編碼原理,生產代碼建議使用 Properties 自動轉義或 Apache Commons Text 成熟庫。掌握 codePoint vs char、補充平面代理對、編碼全鏈路一致性,是處理國際化文本的關鍵。