首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >值中带有反斜杠'\‘的C#格式JSON

值中带有反斜杠'\‘的C#格式JSON
EN

Stack Overflow用户
提问于 2016-04-07 19:17:15
回答 2查看 18.4K关注 0票数 4

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

代码语言:javascript
复制
string extract = @"{""key"": ""\/Date(2015-02-02)\/""}";

如果没有c#字符串转义,则对应于该字符串:

代码语言:javascript
复制
{"key": "\/Date(2015-02-02)\/"}

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

通常,对于格式化,我可能会使用类似JsonConvert的内容,如下所示:

代码语言:javascript
复制
JsonConvert.SerializeObject(JsonConvert.DeserializeObject(extract), Formatting.Indented)

这并不是很有效,因为它将值视为日期,但由于它不是标准MS格式的\/Date(ticks)\/,因此它的日期为1970年1月1日:

代码语言:javascript
复制
{
  "key": "1970-01-01T00:00:02.015+00:00"
}

下一种方法是使用序列化程序设置不转换日期(我并不关心它是否将字段识别为日期,尽管它稍后可能会很方便):

代码语言:javascript
复制
JsonSerializerSettings settings = new JsonSerializerSettings
{
    DateParseHandling = DateParseHandling.None,
};

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

这似乎在反序列化期间将反斜杠视为转义字符,因此一旦我看到最终结果,它就会“丢失”:

代码语言:javascript
复制
{
  "key": "/Date(2015-02-02)/"
}

有没有一种方法可以在C#中格式化JSON (使用或不使用JsonConvert),从而保留值中的反斜杠?

请注意,我正在处理的实际JSON是(a)相当大的,但对于某些regex/find-replace解决方案来说并不太大,如果确实需要的话(b)不在我的控制之下,所以我不能更改格式。我确信答案已经在StackOverflow上了,但我发现很难找到正确的搜索词……

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-04-08 01:37:30

基本问题是,在JSON string文字中,the escaped solidus "\/" means exactly the same as the unescaped solidus "/"和Json.NET在非常低的级别(即JsonTextReader.ReadStringIntoBuffer() )解析和解释这种转义。因此,高层代码无法检测和记住字符串字面量是格式化为"\/Date(2015-02-02)\/"还是"/Date(2015-02-02)/",并在以后适当地写回其中之一。

如果您可以始终将额外的转义添加到以/Date(开头并以)/结尾的字符串中,则可以使用JsonTextWriter的自定义子类来执行此操作:

代码语言:javascript
复制
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进行解析:

代码语言:javascript
复制
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);

这将打印:

密钥{“

”:“\/日期(2015-02-02)\/”}

票数 2
EN

Stack Overflow用户

发布于 2016-04-07 19:33:49

您是否尝试过:

代码语言:javascript
复制
extract = extract.Replace("\\","\\\\");

在解析字符串之前?

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/36474609

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档