使用Newtonsoft反序列化含嵌套引号的JSON问题求助
解决不规范JSON中未转义双引号的反序列化问题
首先得掰扯清楚:你贴的示例"key": "This is just a \"dummy\" value to show the problem"其实是完全合法的标准JSON——内部的\"是正确的转义符,Newtonsoft.Json(Json.NET)绝对能正常解析它。你实际遇到的应该是拿到的JSON不规范,字符串内部的双引号根本没转义,比如长成这样:
"key": "This is just a "dummy" value to show the problem"
这种情况下,Json.NET会把dummy前面的未转义双引号当成字符串的结束标记,直接报错或者截断内容,5万行的文件手动改肯定疯掉,傻愣愣用String.Replace也会把键名的引号一起换掉,完全行不通。
下面给你两个在C#里能用的靠谱方案:
方案1:正则表达式预处理(适合内存足够的场景)
如果你的机器内存能装下整个5万行的JSON文件,用正则精准匹配字符串内部的未转义双引号再替换,是最省心的办法。核心思路是:只替换处于字符串内容里的双引号,别碰结构上的引号(比如"key":前后的那些)。
代码示例:
using System.Text.RegularExpressions; using Newtonsoft.Json; // 读取整个JSON文件到内存 string rawJson = File.ReadAllText("your-huge-file.json"); // 用正则修复字符串内部的未转义双引号 // 正则逻辑:匹配完整的JSON字符串(从"开始,到未转义的"结束),然后在内容里替换未转义的"为\" string fixedJson = Regex.Replace(rawJson, @"(""[^""\\]*(?:\\.[^""\\]*)*)"",?", match => { string content = match.Groups[1].Value; // 替换内容中所有未被转义的双引号 content = Regex.Replace(content, @"(?<!\\)""", @"\"""); // 把修复后的内容放回原来的位置,保留结尾的引号(如果有的话) return content + (match.Value.EndsWith("\"") ? "\"" : ""); }); // 现在就能正常反序列化了 var yourData = JsonConvert.DeserializeObject<YourTargetClass>(fixedJson);
这个正则已经考虑了字符串里的转义字符(比如\\或者\"),不会误处理已经正确转义的内容。
方案2:流式自定义阅读器(适合超大型文件)
如果JSON文件大到内存装不下,那就得用流式处理,继承JsonTextReader自己控制解析逻辑,边读边修复。这种方式不用加载整个文件,内存压力小很多。
代码示例:
using Newtonsoft.Json; using System.IO; using System.Text; public class UnescapedQuoteFixerReader : JsonTextReader { private bool _insideString; private StringBuilder _stringBuffer; public UnescapedQuoteFixerReader(TextReader reader) : base(reader) { } public override bool Read() { if (_insideString) { // 正在读取字符串内容,继续读直到找到未转义的结束引号 int charCode; while ((charCode = base.ReadAsInt32()) != -1) { char c = (char)charCode; if (c == '"') { // 检查前一个字符是不是转义符 if (_stringBuffer.Length > 0 && _stringBuffer[_stringBuffer.Length - 1] == '\\') { // 是转义过的引号,直接加入缓冲区 _stringBuffer.Append(c); } else { // 字符串结束,设置当前token的值 _insideString = false; Value = _stringBuffer.ToString(); TokenType = JsonToken.String; return true; } } else if (c == '\\') { // 遇到转义符,把转义符和下一个字符一起加入缓冲区 _stringBuffer.Append(c); int nextChar = base.ReadAsInt32(); if (nextChar != -1) _stringBuffer.Append((char)nextChar); } else { _stringBuffer.Append(c); } } // 读到流末尾,结束当前字符串 _insideString = false; Value = _stringBuffer.ToString(); TokenType = JsonToken.String; return true; } // 读取非字符串的token bool readSuccess = base.Read(); if (readSuccess && TokenType == JsonToken.String) { // 开始读取新的字符串,初始化缓冲区 _insideString = true; _stringBuffer = new StringBuilder(Value.ToString()); return Read(); // 继续读取字符串剩余内容 } return readSuccess; } } // 使用方式 using (var streamReader = new StreamReader("your-huge-file.json")) using (var jsonReader = new UnescapedQuoteFixerReader(streamReader)) { var serializer = new JsonSerializer(); var yourData = serializer.Deserialize<YourTargetClass>(jsonReader); }
这个阅读器会在读取字符串时自动把内部的未转义双引号处理掉,全程流式操作,不会占太多内存。
小提醒
- 先确认你的问题确实是未转义内部双引号——如果是其他JSON格式错误,比如缺少逗号、括号不匹配,那得另想办法。
- 方案1写起来简单,但要注意内存限制;方案2适合超大文件,但代码稍微复杂点。
- 测试的时候先拿一小段有问题的JSON试,没问题了再跑整个大文件。
内容的提问来源于stack exchange,提问作者paulpizzi
相关产品推荐
相关产品推荐

