2010-06-11 52 views
121

手動創建JSON數據時,我該如何轉義字符串字段?我是否應該使用Apache Commons Lang的StringEscapeUtilities.escapeHtmlStringEscapeUtilities.escapeXml之類的東西,還是應該使用java.net.URLEncoder我應該如何在JSON中轉義字符串?

問題是,當我使用SEU.escapeHtml時,它不會引用引號,並且當我將整個字符串包裝在一對'中時,會生成格式錯誤的JSON。

+14

如果你將整個字符串包裝在一對'''中,你就註定要從頭開始:JSON字符串只能用''''圍繞,見http://www.ietf.org/rfc /rfc4627.txt。 – Thanatos 2010-06-11 04:01:17

+2

對於'StringEscapeUtilities'大綱的+1。它非常有用。 – 2012-11-05 13:33:47

回答

130

理想的情況下,發現在你的語言一個JSON庫,你可以喂一些合適的數據結構,並讓它擔心如何逃脫的事情。它會讓你更加安心。如果因爲某種原因你沒有使用你的語言庫,你不想使用它(我不會建議這個1),或者你正在編寫一個JSON庫,請繼續閱讀。

根據RFC轉義它。 JSON非常自由:只有必須轉義的字符是\,"和控制代碼(任何小於U + 0020的)。

這種轉義結構特定於JSON。你需要一個JSON特定的功能。所有的轉義符都可以寫爲\uXXXX,其中XXXX是該字符的UTF-16編碼單元1。有幾個捷徑,如\\,也可以。 (並且它們導致更小和更清晰的輸出。)

有關全部細節,請參閱the RFC

¹JSON的轉義是建立在JS上的,所以它使用\uXXXX,其中XXXX是一個UTF-16編碼單元。對於BMP之外的代碼點,這意味着編碼代理對,這可能會有點多毛。 (或者,您可以直接輸出字符,因爲JSON的編碼爲Unicode文本,並且允許這些特定字符。)

+0

它在JSON中是否有效,就像在JavaScript中一樣,將字符串括在雙引號或單引號中?或者它只能用double引號? – Behrang 2010-06-11 04:53:37

+7

只有雙引號('「')。 – Thanatos 2010-06-11 05:26:23

+0

{[]}:?:? – Sergei 2014-01-05 15:21:10

3

不確定您的意思是「手動創建json」,但您可以使用像gson http://code.google.com/p/google-gson/),這會將你的HashMap,數組,字符串等轉換爲JSON值。我建議爲此使用一個框架。

+2

通過手動操作,我的意思是不使用Simple JSON,Gson或XStream等JSON庫。 – Behrang 2010-06-11 04:56:35

+0

只是好奇的問題 - 爲什麼你不想使用這些API之一?這就像是試圖手動轉義URL,而不是使用URLEncode/Decode ... – Vladimir 2010-06-11 14:40:57

+1

這些庫不僅僅是URLEncode/Decode的等價物,它們還包括一個完整的序列化包,允許持久化java對象以json的形式,有時你真的只需要編碼一小段文字 – jmd 2011-12-12 10:08:27

2

我沒有花時間,使100%肯定,但它的工作對我的投入,足以通過網上JSON驗證被接受:

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

雖然它不看任何比org.codehaus.jettison.json.JSONObject.quote("your string")

我簡單地使用速度的工具在我的項目已經 - 我的「手動JSON」建設是一個Velocity模板中

22

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 2014-04-03 11:12:09

+0

哪個庫是org.json的一部分?我的班級路徑上沒有它。 – 2018-02-22 12:08:19

+0

https://github.com/fangyidong/json-simple/tree/master/src/main/java/org/json/simple請參閱https://code.google.com/archive/p/json-simple/ – 2018-02-22 12:53:37

46

提液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(); 
    } 
+1

注意:這是Java – 2016-01-16 07:28:11

+5

嗯,這是OP標籤 – MonoThreaded 2016-06-19 01:21:11

+0

只有當c <''時才理解,改爲\ u。在我的情況下,有字符\ ud38D,這是55357和以上'',所以不會改變\ u ... – Stony 2016-11-30 06:38:58

6

StringEscapeUtils.escapeJavaScript/StringEscapeUtils.escapeEcmaScript應該做的伎倆。

+7

'escapeJavaScript'將單引號轉義爲'\'',這是不正確的。 – laurt 2014-05-27 11:59:44

19

Apache commons lang現在支持此功能。只要確保你的類路徑中有最新版本的Apache commons lang。你需要的版本3.2+

發行說明版本3.2

LANG-797:增加逃生/ unescapeJson到StringEscapeUtils。

+0

這對我來說是最實際的答案。大多數項目已經使用apache commons lang,所以不需要爲一個函數添加依賴項。一個JSON構建器可能是最好的答案。 – absmiths 2017-06-28 13:59:30

+0

作爲後續工作,並且由於我無法弄清楚如何編輯評論,我添加了一個新評論,我找到了javax.json.JsonObjectBuilder和javax.json.JsonWriter。非常好的建設者/作家組合。 – absmiths 2017-06-28 14:27:34

2

對於那些誰來到這裏尋找一個命令行的解決方案,像我這樣的,捲曲的--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 [email protected] 'https://www.googleapis.com/freebase/v1/mqlread' 

而現在,這也是關於如何通過命令行查詢的遊離鹼:-)在

3

使用EscapeUtils類的教程commons lang API。

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

JavaScript!== JSON – 2016-01-20 13:25:40

+1

請注意,例如單引號在轉義爲javascript或json時處理方式不同。在commons.lang 3.4中StringEscapeUtils(https://commons.apache.org/proper/commons-lang/javadocs/api-3.4/org/apache/commons/lang3/StringEscapeUtils.html#escapeJson(java.lang.String))有一個escapeJSON方法,它與commons中的escapeJavaScript方法不同。lang 2:https://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/StringEscapeUtils.html#escapeJavaScript(java.lang.String) – GlennV 2016-03-23 15:42:15

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

的方法這裏顯示實際的實現都是錯誤的。
我沒有Java代碼,而只是備案,你可以很容易地轉換這個C#-code:

單項目的禮貌@ 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

「 quote()'方法在其他答案中描述錯誤? – Sandy 2017-04-12 19:46:02

7

org.json.JSONObjectquote(String data)方法做這項工作

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

提取物:

編碼數據作爲JSON字符串。 這適用於引號和任何必要的字符轉義。 [...]空將

+1

'org.apache.sling.commons.json.JSONObject'也有同樣的事情 – 2016-10-25 18:55:25

2

如果您正在使用fastexml傑克遜解釋爲空字符串,可以使用以下命令: com.fasterxml.jackson.core.io.JsonStringEncoder.getInstance().quoteAsString(input)

如果使用Codehaus的傑克遜,你可以使用下面的: org.codehaus.jackson.io.JsonStringEncoder.getInstance().quoteAsString(input)

0

如果您需要逃避JSON JSON字符串內,使用org.json.JSONObject.quote(「需要進行轉義你的JSON字符串」),似乎可以用工作以及

0

的爲\ uXXXX語法CA ñ解決這個問題,谷歌UTF-16的名稱的標誌,你可以找出XXXX,例如:utf-16雙引號

0

我認爲在2017年的最佳答案是使用javax.json API。使用javax.json.JsonBuilderFactory創建您的json對象,然後使用javax.json.JsonWriterFactory編寫對象。非常好的建設者/作家組合。

相關問題