web-dev-qa-db-ja.com

JSONで文字列をエスケープする方法は?

JSONデータを手動で作成するとき、文字列フィールドをエスケープするにはどうすればいいですか? Apache Commons LangのStringEscapeUtilities.escapeHtmlStringEscapeUtilities.escapeXmlのようなものを使うべきですか、それともJava.net.URLEncoderを使うべきですか?

問題は、SEU.escapeHtmlを使用しても引用符がエスケープされず、文字列全体を'のペアで囲むと、不正な形式のJSONが生成されることです。

140
Behrang

理想的には、あなたの言語であなたがに適切なデータ構造を与えることができるJSONライブラリを見つけて、それを心配させてください脱出方法について。それはあなたをずっと安全に保つでしょう。何らかの理由であなたの言語のライブラリを持っていないのなら、それを使いたくない(私はこれをお勧めしません¹)、またはJSONライブラリを書いているのなら、読んでください。

RFCに従ってそれを脱出してください。 JSONはかなりリベラルです:あなたがエスケープしなければならない唯一の文字は\"、および制御コード(U + 0020未満のもの)です。

このエスケープの構造はJSONに固有のものです。 JSON特有の機能が必要です。すべてのエスケープは\uXXXXとして書くことができます。ここでXXXXはその文字のUTF-16コード単位¹です。 \\など、いくつかのショートカットもありますが、これらも同様に機能します。 (そして、それらはより小さくそしてより明確なアウトプットをもたらします。)

詳細については、 RFC を参照してください。

¹JSONのエスケープ処理はJSに基づいているため、\uXXXXを使用します。ここでXXXXはUTF-16コード単位です。 BMP外のコードポイントの場合、これはサロゲートペアをエンコードすることを意味します。 (または、JSONのエンコードはUnicodeテキストであり、これらの特定の文字を使用できるため、直接文字を直接出力することもできます。)

144
Thanatos

から抽出 Jettison

 public static String quote(String string) {
         if (string == null || string.length() == 0) {
             return "\"\"";
         }

         char         c = 0;
         int          i;
         int          len = string.length();
         StringBuilder sb = new StringBuilder(len + 4);
         String       t;

         sb.append('"');
         for (i = 0; i < len; i += 1) {
             c = string.charAt(i);
             switch (c) {
             case '\\':
             case '"':
                 sb.append('\\');
                 sb.append(c);
                 break;
             case '/':
 //                if (b == '<') {
                     sb.append('\\');
 //                }
                 sb.append(c);
                 break;
             case '\b':
                 sb.append("\\b");
                 break;
             case '\t':
                 sb.append("\\t");
                 break;
             case '\n':
                 sb.append("\\n");
                 break;
             case '\f':
                 sb.append("\\f");
                 break;
             case '\r':
                sb.append("\\r");
                break;
             default:
                 if (c < ' ') {
                     t = "000" + Integer.toHexString(c);
                     sb.append("\\u" + t.substring(t.length() - 4));
                 } else {
                     sb.append(c);
                 }
             }
         }
         sb.append('"');
         return sb.toString();
     }
51
MonoThreaded

これを試してみてくださいorg.codehaus.jettison.json.JSONObject.quote("your string")

こちらからダウンロードしてください: http://mvnrepository.com/artifact/org.codehaus.jettison/jettison

36
dpetruha

org.json.simple.JSONObject.escape()は、引用符、\、/、\ r、\ n、\ b、\ f、\ tなどの制御文字をエスケープします。 JavaScriptコードをエスケープするために使用できます。

import org.json.simple.JSONObject;
String test =  JSONObject.escape("your string");
23
Dan-Dev

Apache commons langはこれをサポートします。クラスパスに最新バージョンのApache commons langがあることを確認してください。バージョン3.2以降が必要です。

バージョン3.2のリリースノート

LANG-797:StringEscapeUtilsにescape/unescapeJsonを追加しました。

21
NS du Toit

org.json.JSONObjectquote(String data)メソッドが仕事

import org.json.JSONObject;
String jsonEncodedString = JSONObject.quote(data);

ドキュメントから抽出します。

データをJSON文字列としてエンコードします。 これは引用符と必要な文字のエスケープに適用されます。 [...] NULLは空の文字列として解釈されます

9
I.G. Pascual

StringEscapeUtils.escapeJavaScript/StringEscapeUtils.escapeEcmaScriptもトリックをやるべきです。

6

Fastexml jacksonを使用している場合は、以下を使用できます。com.fasterxml.jackson.core.io.JsonStringEncoder.getInstance().quoteAsString(input)

あなたがcodehaus jacksonを使っているならば、あなたは以下を使うことができます:org.codehaus.jackson.io.JsonStringEncoder.getInstance().quoteAsString(input)

4
Dhiraj

「jsonを手動で作成する」とはどういう意味かわかりませんが、gson( http://code.google.com/p/google-gson/ )のようなものを使用できます。 HashMap、Array、StringなどをJSON値に変換します。私はこれのためのフレームワークを使うことを勧めます。

3
Vladimir

私は100%確実にするために時間を費やしてはいませんが、それは私の入力がオンラインJSONバリデータによって受け入れられるのに十分に働いた:

org.Apache.velocity.tools.generic.EscapeTool.EscapeTool().Java("input")

org.codehaus.jettison.json.JSONObject.quote("your string")ほど見栄えはよくありませんが

私はすでに自分のプロジェクトで単にベロシティツールを使っています - 私の "手動JSON"ビルドはベロシティテンプレートの中にありました

2
Tjunkie

コモンズ言語APIでEscapeUtilsクラスを使用します。

EscapeUtils.escapeJavaScript("Your JSON string");
2
Jsm

私のように、ここでコマンドラインソリューションを探している人のために、cURLの--data-urlencodeは問題なく動作します。

curl -G -v -s --data-urlencode 'query={"type" : "/music/artist"}' 'https://www.googleapis.com/freebase/v1/mqlread'

送る

GET /freebase/v1/mqlread?query=%7B%22type%22%20%3A%20%22%2Fmusic%2Fartist%22%7D HTTP/1.1

、 例えば。より大きなJSONデータをファイルに入れることができ、@構文を使用して、エスケープ対象のデータからSlurpするファイルを指定します。例えば、

$ cat 1.json 
{
  "type": "/music/artist",
  "name": "The Police",
  "album": []
}

あなたが使うだろう

curl -G -v -s --data-urlencode [email protected] 'https://www.googleapis.com/freebase/v1/mqlread'

そして今、これはコマンドラインからFreebaseを問い合わせる方法に関するチュートリアルでもあります:-)

2
vijucat

Moshi 's JsonWriter classを考えてください。それは素晴らしいAPIを持っていて、それは最小限にコピーを減らします、すべてはファイルされた、OutputStreamなどにうまくストリーミングできます。

OutputStream os = ...;
JsonWriter json = new JsonWriter(Okio.buffer(Okio.sink(os)));
json.beginObject();
json.name("id").value(getId());
json.name("scores");
json.beginArray();
for (Double score : getScores()) {
  json.value(score);
}
json.endArray();
json.endObject();

手持ちの文字列が欲しい場合:

Buffer b = new Buffer(); // okio.Buffer
JsonWriter writer = new JsonWriter(b);
//...
String jsonString = b.readUtf8();
1
orip

2017年の最善の答えは、javax.json APIを使用することです。 javax.json.JsonBuilderFactoryを使用してjsonオブジェクトを作成してから、javax.json.JsonWriterFactoryを使用してオブジェクトを書き出します。とても素敵なビルダー/ライターの組み合わせ。

0
absmiths

\ uXXXX構文を使用してこの問題を解決することができます、記号の名前とグーグルUTF-16、あなたはXXXXを見つけることができます、例えば:utf-16二重引用符

0
David

実際の実装を示すここの方法はすべて不完全です。
私はJavaコードを持っていません、しかし単に記録のために、あなたは簡単にこのC#コードを変換することができました:

モノプロジェクトのおかげで@ https://github.com/mono/mono/blob/master/mcs/class/System.Web/System.Web/HttpUtility.cs

public static string JavaScriptStringEncode(string value, bool addDoubleQuotes)
{
    if (string.IsNullOrEmpty(value))
        return addDoubleQuotes ? "\"\"" : string.Empty;

    int len = value.Length;
    bool needEncode = false;
    char c;
    for (int i = 0; i < len; i++)
    {
        c = value[i];

        if (c >= 0 && c <= 31 || c == 34 || c == 39 || c == 60 || c == 62 || c == 92)
        {
            needEncode = true;
            break;
        }
    }

    if (!needEncode)
        return addDoubleQuotes ? "\"" + value + "\"" : value;

    var sb = new System.Text.StringBuilder();
    if (addDoubleQuotes)
        sb.Append('"');

    for (int i = 0; i < len; i++)
    {
        c = value[i];
        if (c >= 0 && c <= 7 || c == 11 || c >= 14 && c <= 31 || c == 39 || c == 60 || c == 62)
            sb.AppendFormat("\\u{0:x4}", (int)c);
        else switch ((int)c)
            {
                case 8:
                    sb.Append("\\b");
                    break;

                case 9:
                    sb.Append("\\t");
                    break;

                case 10:
                    sb.Append("\\n");
                    break;

                case 12:
                    sb.Append("\\f");
                    break;

                case 13:
                    sb.Append("\\r");
                    break;

                case 34:
                    sb.Append("\\\"");
                    break;

                case 92:
                    sb.Append("\\\\");
                    break;

                default:
                    sb.Append(c);
                    break;
            }
    }

    if (addDoubleQuotes)
        sb.Append('"');

    return sb.ToString();
}

これはに圧縮することができます

    // https://github.com/mono/mono/blob/master/mcs/class/System.Json/System.Json/JsonValue.cs
public class SimpleJSON
{

    private static  bool NeedEscape(string src, int i)
    {
        char c = src[i];
        return c < 32 || c == '"' || c == '\\'
            // Broken lead surrogate
            || (c >= '\uD800' && c <= '\uDBFF' &&
                (i == src.Length - 1 || src[i + 1] < '\uDC00' || src[i + 1] > '\uDFFF'))
            // Broken tail surrogate
            || (c >= '\uDC00' && c <= '\uDFFF' &&
                (i == 0 || src[i - 1] < '\uD800' || src[i - 1] > '\uDBFF'))
            // To produce valid JavaScript
            || c == '\u2028' || c == '\u2029'
            // Escape "</" for <script> tags
            || (c == '/' && i > 0 && src[i - 1] == '<');
    }



    public static string EscapeString(string src)
    {
        System.Text.StringBuilder sb = new System.Text.StringBuilder();

        int start = 0;
        for (int i = 0; i < src.Length; i++)
            if (NeedEscape(src, i))
            {
                sb.Append(src, start, i - start);
                switch (src[i])
                {
                    case '\b': sb.Append("\\b"); break;
                    case '\f': sb.Append("\\f"); break;
                    case '\n': sb.Append("\\n"); break;
                    case '\r': sb.Append("\\r"); break;
                    case '\t': sb.Append("\\t"); break;
                    case '\"': sb.Append("\\\""); break;
                    case '\\': sb.Append("\\\\"); break;
                    case '/': sb.Append("\\/"); break;
                    default:
                        sb.Append("\\u");
                        sb.Append(((int)src[i]).ToString("x04"));
                        break;
                }
                start = i + 1;
            }
        sb.Append(src, start, src.Length - start);
        return sb.ToString();
    }
}
0
Stefan Steiger

Apache commons-textに StringEscapeUtils.escapeJson(String) が追加されました。

0
Mohsen

JSON文字列の内側でJSONをエスケープする必要がある場合は、org.json.JSONObject.quote( "エスケープする必要があるjsonの文字列")を使用してください。

0
webjockey