Javaで未だに公式サポートされないJSON
大きなデータの作成は、JacksonやGsonを使う選択肢が普通と思いますが、
小さなデータの作成は、リッチなライブラリに頼らず、簡単な関数で済ませたい。
このような時の悩みの種は文字列のエスケープ処理です。
エスケープ対象は、
対象文字 | Byteコード | エスケープ表記 |
---|---|---|
BS | 0x08 | \b |
HT | 0x09 | \t |
LF | 0x0A | \n |
FF | 0x0C | \f |
CR | 0x0D | \r |
" | 0x22 | " |
/ | 0x2F | / |
\ | 0x5C | \ \ |
コード
文字列を1バイトずつ置換する方式です。
private static String escapeJsonString(CharSequence cs) {
final byte BACKSLASH = 0x5C;
final byte[] BS = new byte[]{BACKSLASH, 0x62}; /* \\b */
final byte[] HT = new byte[]{BACKSLASH, 0x74}; /* \\t */
final byte[] LF = new byte[]{BACKSLASH, 0x6E}; /* \\n */
final byte[] FF = new byte[]{BACKSLASH, 0x66}; /* \\f */
final byte[] CR = new byte[]{BACKSLASH, 0x72}; /* \\r */
try (
ByteArrayOutputStream strm = new ByteArrayOutputStream();
) {
byte[] bb = cs.toString().getBytes(StandardCharsets.UTF_8);
for (byte b : bb) {
if (b == 0x08 /* BS */) {
strm.write(BS);
} else if (b == 0x09 /* HT */) {
strm.write(HT);
} else if (b == 0x0A /* LF */) {
strm.write(LF);
} else if (b == 0x0C /* FF */) {
strm.write(FF);
} else if (b == 0x0D /* CR */) {
strm.write(CR);
} else if (
b == 0x22 /* " */
|| b == 0x2F /* / */
|| b == BACKSLASH /* \\ */
) {
strm.write(BACKSLASH);
strm.write(b);
} else {
strm.write(b);
}
}
return new String(strm.toByteArray(), StandardCharsets.UTF_8);
}
catch (IOException notHappen) {
throw new RuntimeException(notHappen);
}
}
テスト
public static void main(String[] args) {
String before = "abc \b \t \n \f \r / \\ \"";
String escaped = escapeJsonString(before);
System.out.println("{\"value\":\"" + escaped + "\"}");
/* {"value":"abc \b \t \n \f \r \/ \\ \""} */
}