JSON에서 문자열을 어떻게 이스케이프해야합니까?


154

JSON 데이터를 수동으로 생성 할 때 문자열 필드를 어떻게 이스케이프해야합니까? 아파치 코 몬즈 랭의 같은해야 내가 사용 무언가 StringEscapeUtilities.escapeHtml, StringEscapeUtilities.escapeXml또는 사용해야합니까 java.net.URLEncoder?

문제는을 사용할 때 SEU.escapeHtml따옴표를 이스케이프하지 않고 전체 문자열을 's 쌍으로 감싸면 잘못된 JSON이 생성된다는 것입니다.


20
전체 문자열을 한 쌍으로 '줄이면 처음부터 끝납니다. JSON 문자열은로만 둘러 쌀 수 있습니다 ". ietf.org/rfc/rfc4627.txt를 참조하십시오 .
Thanatos

2
StringEscapeUtilities개요 는 +1입니다 . 꽤 유용합니다.
무하마드 Gelbana

답변:


157

언어 에 맞는 적절한 데이터 구조를 제공 할 수 있는 JSON 라이브러리를 찾고 이스케이프 처리 방법에 대해 걱정 하는 것이 이상적 입니다. 훨씬 더 건강하게 유지합니다. 어떤 이유로 든 귀하의 언어로 된 라이브러리가 없다면, 하나를 사용하고 싶지 않거나 (이 제안하지 않을 것 ¹) JSON 라이브러리를 작성하는 경우 계속 읽으십시오.

RFC에 따라 이스케이프 처리하십시오. JSON은 매우 진보적이다 : 당신이 유일한 문자가 있어야 탈출은 \, "제어 코드 (아무것도 덜 U + 0020 이상)합니다.

이스케이프 구조는 JSON에만 해당됩니다. JSON 특정 기능이 필요합니다. 모든 이스케이프는 해당 문자의 UTF-16 코드 단위 ¹가있는 \uXXXX위치 로 작성할 수 있습니다 XXXX. 과 같은 몇 가지 단축키 \\가 있습니다. (그리고 그것들은 더 작고 더 선명한 결과를 낳습니다.)

자세한 내용 은 RFC를 참조하십시오 .

¹JSON의 탈출은 그래서 사용 JS에 내장되는 \uXXXX경우, XXXXUTF-16 코드 유닛이다. BMP 외부의 코드 포인트의 경우 이는 대리 쌍을 인코딩하는 것을 의미하며 약간 털이 될 수 있습니다. (또는 JSON의 인코딩은 유니 코드 텍스트이므로 이러한 특정 문자를 허용하므로 문자를 직접 출력 할 수 있습니다.)


JavaScript에서와 같이 JSON에서 문자열을 큰 따옴표 나 작은 따옴표로 묶는 것이 유효합니까? 아니면 큰 따옴표로 묶는 것만 유효합니까?
Behrang Saeedzadeh

14
큰 따옴표 ( ") 만
Thanatos

3
@Sergei : {[]}:?단일 백 슬래시로 문자 를 이스케이프해서는 안됩니다. ( \:예를 들어, JSON 문자열에서는 유효하지 않습니다.) 모든 \uXXXX바이트는 몇 바이트를 낭비 하면서 구문을 사용하여 선택적으로 이스케이프 할 수 있습니다 . RFC의 §2.5를 참조하십시오.
Thanatos

2
나는 그것이 얼마나 광범위하게 지원되는지 확실하지 않지만, 내 경험상 그 일을하라는 부름 JSON.stringify().
LS

2
@BitTickler 유니 코드 문자는 전혀 모호하지 않습니다. 이는 유니 코드 사양에 코드 포인트가 있다는 것을 의미합니다. std :: string을 사용하면 많은 유니 코드 문자입니다. 직렬화해야 할 때 파일이나 네트워크를 통해 말하면 '인코딩'이 들어오는 곳입니다. Thanatos에 따르면 UTF를 사용하기를 원하지만 기술적으로는 모든 인코딩을 사용할 수있는 한 유니 코드 문자로 재구성 될 수 있습니다.
Gerard ONeill

54

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();
     }

10
음, 이것은 OP 태그였습니다
MonoThreaded

c < ''일 때만 이해하지 말고 \ u로 변경하십시오. 내 경우에는 문자 \ uD38D가 55357 이상이며 ''이상이므로 \ u로 변경되지 않습니다.
Stony

1
@Stony 새로운 질문처럼 들립니다
MonoThreaded

@MonoThreaded 답장을 보내 주셔서 감사합니다. 여전히 이유를 모르겠습니다. 그러나 마지막으로 다음과 같이 수정하기 위해 메소드를 변경했습니다. sb.append ( "\\ u"+ t.substring (t.length ()-4)); } else {sb.append (c); }}
Stony

1
@Stony 이외의 모든 문자 ", \ 및 제어 문자 ( ""전 이들은) 긴 출력 인코딩으로 일치 유효한 인사이드 JSON 문자열이다. 즉, \uD38DUTF 인코딩이 유지되는 한 "펍"을 인코딩 할 필요가 없습니다 .
meustrus

37

이것을보십시오 org.codehaus.jettison.json.JSONObject.quote("your string").

여기에서 다운로드하십시오 : http://mvnrepository.com/artifact/org.codehaus.jettison/jettison


확실히 최고의 솔루션! Thx
Lastnico

그러나 이것은 [{
Sergei

1
@Sergei JSON 문자열 내에서 중괄호를 이스케이프 처리하지 않아도됩니다.
Yobert

이것이 실제로 반환하는 것을 보여주는 데 유용 할 수 있습니다.
Trevor

2
org.json.JSONObject.quote ( "your json string")도 잘 작동합니다.
webjockey

23

org.json.simple.JSONObject.escape ()는 따옴표, \, /, \ r, \ n, \ b, \ f, \ t 및 기타 제어 문자를 이스케이프합니다. JavaScript 코드를 이스케이프 처리하는 데 사용할 수 있습니다.

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

3
사용하는 json 라이브러리 (JSONObject.escape, JSONObject.quote, ..)에 따라 다르지만 항상 인용 작업을 수행하는 정적 메소드이므로 재사용해야합니다.
amine

org.json은 어떤 라이브러리에 속합니까? 내 수업에 없어요.
Alex Spurling


22

Apache commons lang은 이제 이것을 지원합니다. 클래스 경로에 최신 버전의 Apache Commons lang이 있는지 확인하십시오. 버전 3.2 이상이 필요합니다

버전 3.2 릴리스 정보

LANG-797 : StringEscapeUtils에 escape / unescapeJson을 추가했습니다.


이것은 나에게 가장 실용적인 대답입니다. 대부분의 프로젝트는 이미 apache commons lang을 사용하므로 한 함수에 대한 종속성을 추가 할 필요가 없습니다. JSON 빌더가 아마도 가장 좋은 대답 일 것입니다.
absmiths 2016 년

후속 조치로서 주석을 편집하는 방법을 알 수 없으므로 새로운 주석을 추가했습니다. javax.json.JsonObjectBuilder 및 javax.json.JsonWriter를 발견했습니다. 아주 좋은 빌더 / 라이터 조합.
absmiths

1
이것은 apache commons lang에서 더 이상 사용되지 않으므로 apache commons text 를 사용해야 합니다 . 안타깝게도이 라이브러리는 /문자 를 이스케이프 처리하여 선택적 / 오래된 사양을 따릅니다 . 이것은 URL을 가진 JSON을 포함하여 많은 것들을 파괴합니다. 원래의 제안은 /탈출하기 위해 특별한 숯 이었지만, 더 이상 우리 가 글을 쓸 당시 최신 사양에서
adamnfish

10

org.json.JSONObject quote(String data) 방법은 일을한다

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

문서에서 추출하십시오.

데이터를 JSON 문자열로 인코딩합니다. 이것은 따옴표와 필요한 문자 이스케이프를 적용합니다 . [...] Null은 빈 문자열로 해석됩니다.


1
org.apache.sling.commons.json.JSONObject이 같은 일을 가지고
요르단 Shurmer

5

StringEscapeUtils.escapeJavaScript/ StringEscapeUtils.escapeEcmaScript트릭도 수행해야합니다.


10
escapeJavaScript작은 따옴표를로 이스케이프합니다 \'.
laurt

4

fastexml jackson을 사용중인 경우 다음을 사용할 수 있습니다. com.fasterxml.jackson.core.io.JsonStringEncoder.getInstance().quoteAsString(input)

codehaus jackson을 사용하는 경우 다음을 사용할 수 있습니다. org.codehaus.jackson.io.JsonStringEncoder.getInstance().quoteAsString(input)


3

'json 수동으로 생성'의 의미가 확실하지 않지만 gson ( http://code.google.com/p/google-gson/ ) 과 같은 것을 사용할 수 있으며 HashMap, Array, String 등을 변형시킬 수 있습니다. , JSON 값으로. 나는 이것을위한 프레임 워크를 사용하는 것이 좋습니다.


2
수동으로 나는 Simple JSON, Gson 또는 XStream과 같은 JSON 라이브러리를 사용하지 않아야했습니다.
Behrang Saeedzadeh

호기심의 문제-왜 이러한 API 중 하나를 사용하고 싶지 않습니까? URLEncode / Decode를 사용하는 대신 URL을 수동으로 이스케이프하려고하는 것과 같습니다.
Vladimir

1
실제로 동일하지는 않지만 라이브러리에는 URLEncode / Decode에 해당하는 것보다 훨씬 많은 것이 포함되어 있으며 json 형식으로 Java 객체의 지속성을 허용하는 전체 직렬화 패키지를 포함하며 때로는 짧은 텍스트 묶음 만 인코딩하면됩니다
jmd dec

2
작은 데이터 비트를 직렬화하기위한 라이브러리를 포함하지 않으려면 JSON을 수동으로 작성하는 것이 좋습니다.
Aditya Kumar Pandey

2
고품질 라이브러리가있는 곳에서 JSON을 수동으로 생성 해야하는 경우 팀원에게 내가있는 모든 프로젝트에서 제거하도록 요청하고 싶습니다.
Michael Joyce

2

나는 100 % 확실하게하는 데 시간을 소비하지 않았지만 온라인 JSON 유효성 검사기에서 입력을 받아 들일 수있을 정도로 작동했습니다.

org.apache.velocity.tools.generic.EscapeTool.EscapeTool().java("input")

비록 더 나아 보이지는 않지만 org.codehaus.jettison.json.JSONObject.quote("your string")

이미 프로젝트에서 속도 도구를 사용하고 있습니다. "수동 JSON"건물은 속도 템플릿 내에있었습니다.


2

나 같은 명령 행 솔루션을 찾는 사람들에게 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 데이터를 파일에 넣을 수 있으며 @ 구문을 사용하여 이스케이프 될 데이터에서 숨길 파일을 지정합니다. 예를 들어

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

너는 사용할거야

curl -G -v -s --data-urlencode query@1.json 'https://www.googleapis.com/freebase/v1/mqlread'

이제 명령 줄에서 Freebase를 쿼리하는 방법에 대한 자습서이기도합니다.


2

commons lang API에서 EscapeUtils 클래스를 사용하십시오.

EscapeUtils.escapeJavaScript("Your JSON string");

1
예를 들어 작은 따옴표는 javascript 또는 json으로 이스케이프 처리 될 때 다르게 처리됩니다. 3.4 StringEscapeUtils (commons.lang에서 commons.apache.org/proper/commons-lang/javadocs/api-3.4/org/...을 :) 2 commons.lang escapeJavaScript의 방법과 다른 방법 escapeJSON 갖는다 commons.apache한다. org / proper / commons-lang / javadocs / api-2.6 / org /…
GlennV

1

MoshiJsonWriter 클래스를 고려하십시오 . 그것은 훌륭한 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();


0

JSON 문자열 내에서 JSON을 이스케이프해야하는 경우 org.json.JSONObject.quote ( "이스케이프해야하는 json 문자열")를 사용하십시오.


0

\ uXXXX 구문을 사용하면이 문제를 해결할 수 있습니다 .Google UTF-16 기호 이름으로 XXXX를 찾을 수 있습니다 (예 : utf-16 큰 따옴표)


0

실제 구현을 보여주는 여기의 방법은 모두 잘못되었습니다.
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();
    }
}

quote()다른 답변에 설명 된 방법은 어떻게 잘못됩니까?
Sandy

0

2017 년 가장 좋은 대답은 javax.json API를 사용하는 것입니다. javax.json.JsonBuilderFactory를 사용하여 json 오브젝트를 작성한 후 javax.json.JsonWriterFactory를 사용하여 오브젝트를 작성하십시오. 아주 좋은 빌더 / 라이터 조합.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.