最近工作中遇到需要調用第三方接口的需求。第三方接口返回的字符串中,會把中文轉義成 \u + Unicode 的形式。因此,我需要再把 \u + Unicode 轉換成漢字。
這裏,我們需要認識到 Java 代碼對於 \u 字符處理的內外有別。如果是編寫程序的時候,直接在字符串變量裏面寫 \u + Unicode ,Java 會自動轉成漢字。但是 Java 程序對於從外部輸入的 \u + Unicode 字符,會把 \u 視作普通字符,相當於 Java 字符串中的 "\\u"
。
下面是工具類代碼,用於把 \u + Unicode 轉換成漢字。
package zhangchao.common.unicode;
import java.util.regex.Pattern;
/**
* 字符串中存在 反斜槓+u 開頭 的Unicode字符。本類用於把那些Unicode字符串轉換成漢字
* @author 張超
*
*/
public final class UicodeBackslashU {
// 單個字符的正則表達式
private static final String singlePattern = "[0-9|a-f|A-F]";
// 4個字符的正則表達式
private static final String pattern = singlePattern + singlePattern +
singlePattern + singlePattern;
/**
* 把 \\u 開頭的單字轉成漢字,如 \\u6B65 -> 步
* @param str
* @return
*/
private static String ustartToCn(final String str) {
StringBuilder sb = new StringBuilder().append("0x")
.append(str.substring(2, 6));
Integer codeInteger = Integer.decode(sb.toString());
int code = codeInteger.intValue();
char c = (char)code;
return String.valueOf(c);
}
/**
* 字符串是否以Unicode字符開頭。約定Unicode字符以 \\u開頭。
* @param str 字符串
* @return true表示以Unicode字符開頭.
*/
private static boolean isStartWithUnicode(final String str) {
if (null == str || str.length() == 0) {
return false;
}
if (!str.startsWith("\\u")) {
return false;
}
// \u6B65
if (str.length() < 6) {
return false;
}
String content = str.substring(2, 6);
boolean isMatch = Pattern.matches(pattern, content);
return isMatch;
}
/**
* 字符串中,所有以 \\u 開頭的UNICODE字符串,全部替換成漢字
* @param strParam
* @return
*/
public static String unicodeToCn(final String str) {
// 用於構建新的字符串
StringBuilder sb = new StringBuilder();
// 從左向右掃描字符串。tmpStr是還沒有被掃描的剩餘字符串。
// 下面有兩個判斷分支:
// 1. 如果剩餘字符串是Unicode字符開頭,就把Unicode轉換成漢字,加到StringBuilder中。然後跳過這個Unicode字符。
// 2.反之, 如果剩餘字符串不是Unicode字符開頭,把普通字符加入StringBuilder,向右跳過1.
int length = str.length();
for (int i = 0; i < length;) {
String tmpStr = str.substring(i);
if (isStartWithUnicode(tmpStr)) { // 分支1
sb.append(ustartToCn(tmpStr));
i += 6;
} else { // 分支2
sb.append(str.substring(i, i + 1));
i++;
}
}
return sb.toString();
}
}
下面我們要測試一下代碼。我們讀取了一個JSON文件,文件中有 \u + Unicode 的內容。
讀取文件的 FileUtils.java:
package zhangchao.common.utils;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* 文件工具類
* @author 張超
*
*/
public final class FileUtils {
/**
* 讀取文件內容,並把內容作爲字符串返回
* @param f 要讀取的文件
* @return 字符串形式的文件內容。
*/
public static String readAsString(File f) {
BufferedReader br = null;
StringBuilder sb = new StringBuilder();
try {
br = new BufferedReader(new InputStreamReader(new FileInputStream(f)));
String str = br.readLine();
while (null != str) {
sb.append(str).append("\n");
str = br.readLine();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (null != br) {
br.close();
br = null;
}
} catch (IOException e) {
e.printStackTrace();
}
}
return sb.toString();
}
}
用於測試的主類,TestUnicode.java:
package zhangchao.test;
import zhangchao.common.utils.FileUtils;
import zhangchao.common.unicode.UicodeBackslashU;
import java.io.File;
/**
* 測試 \\u + Unicode 轉換成漢字
* @author 張超
*
*/
public class TestUnicode {
public static void main(String[] args) {
String jsonStr = FileUtils.readAsString(new File("src/test/resources/MyJson.json"));
String str = UicodeBackslashU.unicodeToCn(jsonStr);
System.out.println(str);
}
}
MyJson.json 的文件內容:
{
"msg":"success",
"data":{
"userId":"12363324",
"collegeName":"\u8BA1\u7B97\u673A\u5B66\u9662",
"className":"\u8F6F\u4EF6\u4E00\u73ED"
}
}
程序的運行結果:
{
"msg":"success",
"data":{
"userId":"12363324",
"collegeName":"計算機學院",
"className":"軟件一班"
}
}
下面的圖片解釋了 UicodeBackslashU 類的工作原理: