JSON 문자열을 이스케이프하는 방법?


99

쉬운 JSON 이스케이프에 사용할 수있는 클래스 / 함수가 있습니까? 차라리 직접 쓸 필요는 없습니다.


4
JsonConvert.ToString ()이 나를 위해 일했습니다.
Martin Lottering 2017 년

트윗 담아 가기 json을 형식이 지정된 문자열로 만드는 방법을 찾고 있습니다. 아래 답변 중 어느 것도 효과가 없었지만 효과가있었습니다.
GhostShaman

답변:



50

Newtonsoft의 매우 인기있는 Json.Net 프로젝트를 사용하는 사람들에게는 작업이 간단합니다.

using Newtonsoft.Json;

....
var s = JsonConvert.ToString(@"a\b");
Console.WriteLine(s);
....

이 코드는 다음을 인쇄합니다.

"a \\ b"

즉, 결과 문자열 값에는 따옴표와 이스케이프 된 백 슬래시가 포함됩니다.


2
인코딩되고 이스케이프 된 unc 경로를 역 직렬화하기 위해이 메서드를 재현 할 수 없습니다. 내 길은 용납 할 수없는 "WatchedPath": "\\\\myserver\\output"것이된다 "\"\\\\\\\\myserver\\\\output\"".
slestak

3
위의 방법은 역 직렬화를위한 것이 아닙니다. 평가자는 JSON 텍스트를 수동으로 만들고 C # 문자열이 있고 적절한 텍스트 표현을 가져와야 할 때 사용됩니다.
Dror Harari 2014

@slestak, 나는 당신이 여기에 있었던 것과 같은 문제에 직면하고 있다고 생각합니다. 해결책을 찾았습니까?
GP24

@ GP24 IIRC, 그렇지 않았습니다. 죄송합니다. 더 이상 정보가 없습니다.
slestak

얼마든지 요. 답장 해 주셔서 감사합니다. 도움이된다면 이렇게했습니다 : yourAnnoyingDoubleEncodedString.Replace ( "\\\\", "\\"). Replace ( "\\\" ","\ "");
GP24

40

Dejan의 답변을 바탕으로 할 수있는 작업은 .NET Framework 어셈블리를 가져온System.Web.Helpers 후 다음 함수를 사용하는 것입니다.

static string EscapeForJson(string s) {
  string quoted = System.Web.Helpers.Json.Encode(s);
  return quoted.Substring(1, quoted.Length - 2);
}

Substring때문에 호출이 필요합니다 Encode자동으로 따옴표로 문자열을 둘러싸고 있습니다.


System.Web.Helpers과 같은 닷넷 4.0 전에 사용할 수 없습니다
SERG

… Visual Studio 2015에서는 더 이상 없습니다.
lapo

5
이것은 ASP.NET Web Pages 2.0의 일부입니다. NuGet을 사용하여 추가 할 수 있습니다. 프레임 워크의 일부가 아닙니다.
Murven

31

예, Utils 클래스 또는 기타에 다음 함수를 추가하십시오.

    public static string cleanForJSON(string s)
    {
        if (s == null || s.Length == 0) {
            return "";
        }

        char         c = '\0';
        int          i;
        int          len = s.Length;
        StringBuilder sb = new StringBuilder(len + 4);
        String       t;

        for (i = 0; i < len; i += 1) {
            c = s[i];
            switch (c) {
                case '\\':
                case '"':
                    sb.Append('\\');
                    sb.Append(c);
                    break;
                case '/':
                    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" + String.Format("X", c);
                        sb.Append("\\u" + t.Substring(t.Length - 4));
                    } else {
                        sb.Append(c);
                    }
                    break;
            }
        }
        return sb.ToString();
    }

3
왜 탈출해야 /합니까?
drzaus

나는 이것이 오래된 대답이라는 것을 알고 있으며 외부 라이브러리에 의존하고 싶지 않았기 때문에 이것이 주어 졌음을 기쁘게 생각하지만 제어 문자의 기본 케이스는 항상 "\\ u000X"를 반환한다는 것을 알았습니다. 나는 당신이 먼저 char을 int로 캐스팅해야한다고 믿습니다. 교체 고려string t = "000" + ((int)c).ToString("X");
Jan Discart

올바른 기본 케이스는 다음과 같아야합니다.t = "000" + String.Format("{0:X}",(int) c);
daniatic

16

다음 코드를 사용하여 json의 문자열 값을 이스케이프했습니다. 다음 코드의 출력에 ' "'를 추가해야합니다.

public static string EscapeStringValue(string value)
{
    const char BACK_SLASH = '\\';
    const char SLASH = '/';
    const char DBL_QUOTE = '"';

    var output = new StringBuilder(value.Length);
    foreach (char c in value)
    {
        switch (c)
        {
            case SLASH:
                output.AppendFormat("{0}{1}", BACK_SLASH, SLASH);
                break;

            case BACK_SLASH:
                output.AppendFormat("{0}{0}", BACK_SLASH);
                break;

            case DBL_QUOTE:
                output.AppendFormat("{0}{1}",BACK_SLASH,DBL_QUOTE);
                break;

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

    return output.ToString();
}

1
이것은 정말로 내 하루를 구했습니다. 감사합니다!
casaout

8
프로덕션에서이 코드를 사용하지 마십시오! 이 JSON 이스케이프는 중요한 특수 문자를 누락합니다. 참조 : stackoverflow.com/a/33799784
vog

2
이 코드는 모든 특수한 경우를 포함하지 않습니다. 프로덕션에서 사용하지 마십시오.
Envil

2
좋은 대답없는 바퀴를 재발견하고, 특별한 경우에 몇 가지 버그를 소개합니다
Xilmiki

6

여기에 제공된 방법이 잘못되었습니다.
System.Web.HttpUtility.JavaScriptEncode를 사용할 수 있는데 왜 그렇게 멀리 모험합니까?

낮은 프레임 워크를 사용하는 경우 mono에서 복사하여 붙여 넣기 만하면됩니다.

모노 프로젝트 @ 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();
    }
}


4

긴 문자열과 짧은 문자열에 대해 이러한 답변 중 일부에 대해 속도 테스트를 실행했습니다. Clive Paterson의 코드 는 아마도 다른 사람들이 직렬화 옵션을 고려하고 있기 때문에 좋은 점수를 받았습니다. 내 결과는 다음과 같습니다.

Apple Banana
System.Web.HttpUtility.JavaScriptStringEncode: 140ms
System.Web.Helpers.Json.Encode: 326ms
Newtonsoft.Json.JsonConvert.ToString: 230ms
Clive Paterson: 108ms

\\some\long\path\with\lots\of\things\to\escape\some\long\path\t\with\lots\of\n\things\to\escape\some\long\path\with\lots\of\"things\to\escape\some\long\path\with\lots"\of\things\to\escape
System.Web.HttpUtility.JavaScriptStringEncode: 2849ms
System.Web.Helpers.Json.Encode: 3300ms
Newtonsoft.Json.JsonConvert.ToString: 2827ms
Clive Paterson: 1173ms

다음은 테스트 코드입니다.

public static void Main(string[] args)
{
    var testStr1 = "Apple Banana";
    var testStr2 = @"\\some\long\path\with\lots\of\things\to\escape\some\long\path\t\with\lots\of\n\things\to\escape\some\long\path\with\lots\of\""things\to\escape\some\long\path\with\lots""\of\things\to\escape";

    foreach (var testStr in new[] { testStr1, testStr2 })
    {
        var results = new Dictionary<string,List<long>>();

        for (var n = 0; n < 10; n++)
        {
            var count = 1000 * 1000;

            var sw = Stopwatch.StartNew();
            for (var i = 0; i < count; i++)
            {
                var s = System.Web.HttpUtility.JavaScriptStringEncode(testStr);
            }
            var t = sw.ElapsedMilliseconds;
            results.GetOrCreate("System.Web.HttpUtility.JavaScriptStringEncode").Add(t);

            sw = Stopwatch.StartNew();
            for (var i = 0; i < count; i++)
            {
                var s = System.Web.Helpers.Json.Encode(testStr);
            }
            t = sw.ElapsedMilliseconds;
            results.GetOrCreate("System.Web.Helpers.Json.Encode").Add(t);

            sw = Stopwatch.StartNew();
            for (var i = 0; i < count; i++)
            {
                var s = Newtonsoft.Json.JsonConvert.ToString(testStr);
            }
            t = sw.ElapsedMilliseconds;
            results.GetOrCreate("Newtonsoft.Json.JsonConvert.ToString").Add(t);

            sw = Stopwatch.StartNew();
            for (var i = 0; i < count; i++)
            {
                var s = cleanForJSON(testStr);
            }
            t = sw.ElapsedMilliseconds;
            results.GetOrCreate("Clive Paterson").Add(t);
        }

        Console.WriteLine(testStr);
        foreach (var result in results)
        {
            Console.WriteLine(result.Key + ": " + Math.Round(result.Value.Skip(1).Average()) + "ms");
        }
        Console.WriteLine();
    }

    Console.ReadLine();
}


2
String.Format("X", c);

다음과 같이 출력됩니다. X

대신 이것을 시도하십시오.

string t = ((int)c).ToString("X");

sb.Append("\\u" + t.PadLeft(4, '0'));

2

나는 좋은 한 줄짜리, 다른 사람들처럼 JsonConvert를 사용했지만 추가 된 따옴표와 백 슬래시를 제거하기 위해 하위 문자열을 추가했습니다.

 var escapedJsonString = JsonConvert.ToString(JsonString).Substring(1, JsonString.Length - 2);



0

나는 System.Web.Script.Serialization.JavaScriptSerializer.

다음과 같이 정의 된 작은 정적 도우미 클래스가 있습니다.

internal static partial class Serialization
{
    static JavaScriptSerializer serializer;
    
    static Serialization()
    {
        serializer = new JavaScriptSerializer();
        serializer.MaxJsonLength = Int32.MaxValue;
    }
    public static string ToJSON<T>(T obj)
    {
        return serializer.Serialize(obj);
    }
    public static T FromJSON<T>(string data)
    {
        if (Common.IsEmpty(data))
            return default(T);
        else
            return serializer.Deserialize<T>(data);
    }
}

내가 호출하는 모든 것을 직렬화하려면 Serialization.ToJSON(itemToSerialize)

deserialize하려면 전화 Serialization.FromJSON<T>(jsonValueOfTypeT)

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