最近工作中遇到需要调用第三方接口的需求。第三方接口返回的字符串中,会把中文转义成 \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 类的工作原理: