C#如何使用反斜杠'\'格式化JSON中的值

4

我有一些来自第三方系统的JSON,其中包含值中的反斜杠。例如:

string extract = @"{""key"": ""\/Date(2015-02-02)\/""}";

不经过 C# 字符串转义的对应字符串为:

{"key": "\/Date(2015-02-02)\/"}

我希望能够对这个JSON格式化(如缩进)。

通常,为了格式化,我会使用类似JsonConvert的工具,例如:

JsonConvert.SerializeObject(JsonConvert.DeserializeObject(extract), Formatting.Indented)

这种方法不太可行,因为它将该值视为日期,但由于它不符合标准的 MS 格式 \/Date(ticks)\/,所以它会被视为 1970 年 1 月 1 日的日期:

{
  "key": "1970-01-01T00:00:02.015+00:00"
}

下一种方法是使用序列化器设置来不转换日期(我不介意它是否将字段识别为日期,尽管后面可能会很方便):
JsonSerializerSettings settings = new JsonSerializerSettings
{
    DateParseHandling = DateParseHandling.None,
};

JsonConvert.SerializeObject(JsonConvert.DeserializeObject(extract, settings), Formatting.Indented);

在反序列化过程中,似乎将反斜杠视为转义字符,因此一旦查看最终结果,它就会"丢失":

{
  "key": "/Date(2015-02-02)/"
}

有没有一种在C#中格式化JSON的方法(无论是使用JsonConvert还是其他方式),可以保留值中的反斜杠?

请注意,我处理的实际JSON(a)相当大,但如果真的必要,不太大也不会使用一些regex/find-replace解决方案,(b)不受我的控制,所以我无法更改格式。 我确信答案已经在StackOverflow上了,但是我发现很难找到正确的搜索词...


在C#中,双反斜杠用于将反斜杠表示为字符串。 - derloopkat
2个回答

4

你尝试过以下方法吗:

extract = extract.Replace("\\","\\\\");

在解析字符串之前需要做些什么?


这个可以工作,但感觉有点凌乱。更精确地说,以下代码可以完成任务 - 在结尾撤销替换:JsonConvert.SerializeObject(JsonConvert.DeserializeObject(extract.Replace("\\", "\\\\"), settings), Formatting.Indented).Replace("\\\\", "\\") - jlb83
是的,它有点凌乱,但是考虑到输入的复杂性,我怀疑你将被迫使用此解决方案或类似的东西。反斜杠有时很难序列化/解析。 - Adam Calvet Bohl

2
基本问题在于,在JSON字符串文字中,转义的斜杠"\/"与未转义的斜杠"/"完全相同,而Json.NET在非常低的级别上解析和解释了这种转义,即JsonTextReader.ReadStringIntoBuffer()。因此,高级别代码无法检测和记住字符串文字是格式化为"\/Date(2015-02-02)\/"还是"/Date(2015-02-02)/",并稍后根据需要写回其中之一。
如果您可以始终向以/Date(开头且以)/结尾的字符串添加额外的转义,则可以使用JsonTextWriter的自定义子类来执行此操作:
public class DateLiteralJsonTextWriter : JsonTextWriter
{
    public DateLiteralJsonTextWriter(TextWriter writer) : base(writer) { }

    public override void WriteValue(string value)
    {
        const string startToken = @"/Date(";
        const string replacementStartToken = @"\/Date(";
        const string endToken = @")/";
        const string replacementEndToken = @")\/";

        if (value != null && value.StartsWith(startToken) && value.EndsWith(endToken))
        {
            var sb = new StringBuilder();

            // Add the initial quote.
            sb.Append(QuoteChar);

            // Add the new start token.
            sb.Append(replacementStartToken);

            // Add any necessary escaping to the innards of the "/Date(.*)/" string.
            using (var writer = new StringWriter(sb))
            using (var jsonWriter = new JsonTextWriter(writer) { StringEscapeHandling = this.StringEscapeHandling, Culture = this.Culture, QuoteChar = '\"' })
            {
                var content = value.Substring(startToken.Length, value.Length - startToken.Length - endToken.Length);
                jsonWriter.WriteValue(content);
            }

            // Strip the embedded quotes from the above.
            sb.Remove(replacementStartToken.Length + 1, 1);
            sb.Remove(sb.Length - 1, 1);

            // Add the replacement end token and final quote.
            sb.Append(replacementEndToken);
            sb.Append(QuoteChar);

            // Write without any further escaping.
            WriteRawValue(sb.ToString());
        }
        else
        {
            base.WriteValue(value);
        }
    }
}

然后按照您目前的方式使用 DateParseHandling = DateParseHandling.None 进行解析:
var settings = new JsonSerializerSettings { DateParseHandling = DateParseHandling.None };

var sb = new StringBuilder();
using (var writer = new StringWriter(sb))
using (var jsonWriter = new DateLiteralJsonTextWriter(writer) { Formatting = Formatting.Indented})
{
    JsonSerializer.CreateDefault(settings).Serialize(jsonWriter,  JsonConvert.DeserializeObject(extract, settings));
}

Console.WriteLine(sb);

这将打印:

{
  "key": "\/Date(2015-02-02)\/"
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接