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

时间:2017-03-29 11:07:13

标签: json gson

查看下面的代码。我有一个包含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":"Tikrovi\u0161kai para\u0161ytas k\u016brinys"}
    // {"description":"Tikroviškai parašytas kūrinys"}
}

2 个答案:

答案 0 :(得分:1)

不幸的是,Gson似乎并不支持它。所有JSON输入/输出分别集中在Gson(自2.8.0)JsonReaderJsonWriterJsonReader可以使用其私有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();
    }

}

本作者未经过充分测试,不尊重\u2028\u2029。然后在调用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 \ u016​​1kai para \ u016​​1ytas k \ u016​​brinys”}
  {“description”:“Tikrovi \ u016​​1kai para \ u016​​1ytas k \ u016​​brinys”}

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

答案 1 :(得分:0)

有一个问题被标记为与该问题重复的问题:unicode characters in json file to be unconverted after managing java gson [duplicate] 。我回答了这个问题,答案被认为是适当的解决方案。因此,下面是我的答案的副本:

实际上,unicode字符的一大优势在于,任何客户端都可以读取和处理与字符表示形式相同的代码“ \ u ...”。例如,如果在html文件中,如果将每个字符替换为其unicode表示形式,则浏览器将照常读取它。即将“ Hello world”中的“ H”替换为“ \ u0048”(对于“ H”而言是Unicode),在浏览器中您仍会看到“ Hello world”。但是在这种情况下,它对您不利,因为Gson只是将unicode替换为其符号。

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

您可以这样做:

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

它将为您提供字符串:"\u0048\u0065\u006c\u006c\u006f\u0020\u0077\u006f\u0072\u006c\u0064",然后您可以执行以下操作:

    String s 
= StringUnicodeEncoderDecoder.decodeUnicodeSequenceToString("\u0048\u0065\u006c\u006c\u006f\u0020\u0077\u006f\u0072\u006c\u0064");

它将返回字符串“ Hello world”。它适用于任何语言。以下是文章的链接,该文章解释了在何处获取库:Open Source Java library with stack trace filtering, Silent String parsing Unicode converter and Version comparison。查找标题为“ 字符串Unicode转换器

的段落

这里是Maven artifacts的链接,这里是包含资源和Javadoc的Github的链接。这里是javadoc