Gson Unicode 字符转换为 Unicode 字符代码



在下面查看我的代码。我有一个包含 Unicode 字符代码的 JSON 字符串。我将其转换为我的 Java 对象,然后将其转换回 JSON 字符串。但是,可以看到输入和输出 JSON 字符串不匹配。是否可以使用 Gson 将我的对象转换为原始 JSON 字符串?我希望outputJsoninputJson一样。

static class Book {
String description;
}
public static void test() {
Gson gson = new Gson();
String inputJson = "{"description":"Tikrovi\u0161kai para\u0161ytas k\u016brinys"}";
Book book = gson.fromJson(inputJson, Book.class);
String outputJson = gson.toJson(book);
System.out.println(inputJson);
System.out.println(outputJson);
// Prints:
// {"description":"Tikroviu0161kai parau0161ytas ku016brinys"}
// {"description":"Tikroviškai parašytas kūrinys"}
}

不幸的是,Gson似乎不支持它。所有 JSON 输入/输出分别集中在 Gson(截至 2.8.0)JsonReaderJsonWriter中。JsonReader可以使用其私有readEscapeCharacter方法读取 Unicode 转义。但是,与JsonReader不同的是,JsonWriter只是将一个字符串写入后备Writer实例,除了u2028

u2029之外,不会对127以上的字符进行字符更正。您可能在这里唯一可以做的是编写一个自定义转义Writer以便您可以发出 Unicode 转义。

final class EscapedWriter
extends Writer {
private static final char[] hex = {
'0', '1', '2', '3',
'4', '5', '6', '7',
'8', '9', 'a', 'b',
'c', 'd', 'e', 'f'
};
private final Writer writer;
// I/O components are usually implemented in not thread-safe manner
// so we can save some time on constructing a single UTF-16 escape
private final char[] escape = { '\', 'u', 0, 0, 0, 0 };
EscapedWriter(final Writer writer) {
this.writer = writer;
}
// This implementation is not very efficient and is open for enhancements:
// * constructing a single "normalized" buffer character array so that it could be passed to the downstream writer
//   rather than writing characters one by one
// * etc...
@Override
public void write(final char[] buffer, final int offset, final int length)
throws IOException {
for ( int i = offset; i < length; i++ ) {
final int ch = buffer[i];
if ( ch < 128 ) {
writer.write(ch);
} else {
escape[2] = hex[(ch & 0xF000) >> 12];
escape[3] = hex[(ch & 0x0F00) >> 8];
escape[4] = hex[(ch & 0x00F0) >> 4];
escape[5] = hex[ch & 0x000F];
writer.write(escape);
}
}
}
@Override
public void flush()
throws IOException {
writer.flush();
}
@Override
public void close()
throws IOException {
writer.close();
}
// Some java.io.Writer subclasses may use java.lang.Object.toString() to materialize their accumulated state by design
// so it has to be overridden and forwarded as well
@Override
public String toString() {
return writer.toString();
}
}

这位作者没有经过充分测试,不尊重u2028u2029.然后只需在调用toJson方法时配置输出目标:

final String input = "{"description":"Tikrovi\u0161kai para\u0161ytas k\u016brinys"}";
final Book book = gson.fromJson(input, Book.class);
final Writer output = new EscapedWriter(new StringWriter());
gson.toJson(book, output);
System.out.println(input);
System.out.println(output);

输出:

{"description":"Tikrovi\u0161kai para\u0161ytas k\u016brinys"}{"description":"Tikrovi\u0161kai para\u0161ytas k\u016brinys"}

这是一个有趣的问题,您可能还会在 google/gson 上提出一个问题来添加字符串写入配置选项 - 或者至少从开发团队那里获得一些评论。我确实相信他们非常了解这种行为,并通过设计使其像这样工作,但是他们也可以对此有所了解(我现在唯一能想到的是,目前他们有更多的性能,在编写字符串之前不进行额外的转换,但这是一个微弱的猜测)。

有一个问题被标记为重复的问题:在管理 Java gson 后,将取消转换 json 文件中的 unicode 字符 [重复] .我回答了这个问题,答案被接受为适当的解决方案。所以下面是我的答案的副本:

实际上,unicode 字符的最大优点是任何客户端都读取并处理代码"\u..."和它的人物表现一样。例如,如果在 html 文件中,如果将每个字符替换为其 unicode 表示形式,浏览器将像往常一样读取它。即,将"Hello world"中的"H"替换为"\u0048"(这是"H"的Unicode),在浏览器中您仍然会看到"Hello world"。但在这种情况下,它对您不利,因为 Gson 只是用它们的符号替换 unicode。

我的建议可能并不完美,但它会奏效。在转换对象之前,请记住 unicode 符号的位置,并在转换后将它们更改回 unicode。这里有一个可以帮助您的工具:有一个开源库MgntUtils(由我编写),它有一个实用程序,可以将任何字符串转换为Unicode序列,反之亦然。

你可以做:

String s = StringUnicodeEncoderDecoder.encodeStringToUnicodeSequence("Hello world");

它会给你字符串:"u0048u0065u006cu006cu006fu0020u0077u006fu0072u006cu0064"然后你可以这样做:

String s 
= StringUnicodeEncoderDecoder.decodeUnicodeSequenceToString("u0048u0065u006cu006cu006fu0020u0077u006fu0072u006cu0064");

它会返回字符串"你好世界"。 它适用于任何语言。以下是解释从何处获取库的文章的链接:具有堆栈跟踪过滤的开源 Java 库、静默字符串解析 Unicode 转换器和版本比较。查找标题为">字符串 Unicode 转换器"的段落

这是Maven工件的链接,这里是Github的链接,其中包含源代码和javadoc。这是javadoc

您可以在输入流上调用String.replace("\", "\\"),以欺骗 Gson 并使其不这样解释转义字符。然后通过对输出字符串调用String.replace("\\", "\")来反转这种情况。

最新更新