PowerShell解析含重复键的非标准JSON配置文件方案咨询
处理带重复
_Comment键的类JSON配置文件:解析后还原注释 问题背景
我有一批类JSON格式的配置文件,示例内容如下:
{ "_Comment":"This is not valid, but required or it breaks the program", "_Comment":"If there is only one of these, standard Converters work", "_Comment":"But, there are multiple of these lines", "Name":"Some Body", "Address1":"123 Name of Street", "City":"Some Town", "ST":"AZ", "Zip":"01234-5678", "ItemCount": 101 }
这类文件不符合标准JSON规范(存在重复的_Comment键),移除所有_Comment/_Comments行后才能被标准解析器处理。但如果保存修改后的文件时不还原这些注释行,依赖该配置的应用会出现故障。需要实现移除注释解析、保存时还原注释的操作,优先用PowerShell实现,也可参考其他语言方案。
PowerShell 实现方案
核心思路是:读取文件时分离注释行与有效JSON内容,解析修改后再将注释插回原位置(或原顺序)。
1. 读取并解析配置(分离注释)
# 替换为你的配置文件路径 $configPath = ".\your-config.json" # 读取所有行,保留换行符信息 $allLines = (Get-Content -Path $configPath -Raw -Encoding UTF8) -Split "`n" # 分离注释行和有效JSON行,同时记录注释行的原始位置 $commentEntries = @() $jsonLines = @() for ($i = 0; $i -lt $allLines.Count; $i++) { $line = $allLines[$i].TrimStart() if ($line -match '^"_Comment(s?)":') { $commentEntries += [PSCustomObject]@{ Index = $i Line = $allLines[$i] } } else { $jsonLines += $allLines[$i] } } # 拼接有效JSON并解析为PowerShell对象 $validJson = ($jsonLines -Join "`n") | ConvertFrom-Json
2. 修改配置并保存(还原注释)
# 示例:修改配置项 $validJson.ItemCount = 200 $validJson.Name = "Updated Name" # 将修改后的对象转为格式化的JSON,拆分为行 $modifiedJsonLines = ($validJson | ConvertTo-Json -Depth 100) -Split "`n" # 将注释行插回原始位置(倒序插入避免索引偏移) $finalLines = [System.Collections.Generic.List[string]]$modifiedJsonLines foreach ($entry in $commentEntries | Sort-Object Index -Descending) { if ($entry.Index -lt $finalLines.Count) { $finalLines.Insert($entry.Index, $entry.Line) } else { $finalLines.Add($entry.Line) } } # 保存最终内容到文件 $finalLines -Join "`n" | Set-Content -Path $configPath -Encoding UTF8
C# 参考实现
如果项目需要用编译型语言,以下是C#的核心思路代码:
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text.Json; class Program { static void Main() { string configPath = @"C:\path\to\config.json"; string[] allLines = File.ReadAllLines(configPath); // 记录注释行的位置和内容 var commentPositions = new List<(int Index, string Line)>(); var jsonLines = new List<string>(); for (int i = 0; i < allLines.Length; i++) { string trimmedLine = allLines[i].TrimStart(); if (trimmedLine.StartsWith("\"_Comment") || trimmedLine.StartsWith("\"_Comments")) { commentPositions.Add((i, allLines[i])); } else { jsonLines.Add(allLines[i]); } } // 解析有效JSON string jsonContent = string.Join(Environment.NewLine, jsonLines); var config = JsonSerializer.Deserialize<Config>(jsonContent); // 修改配置项 config.ItemCount = 200; config.Name = "Updated Name"; // 序列化回格式化JSON string modifiedJson = JsonSerializer.Serialize(config, new JsonSerializerOptions { WriteIndented = true }); string[] modifiedLines = modifiedJson.Split(Environment.NewLine); // 插入注释行到原位置 var finalLines = new List<string>(modifiedLines); foreach (var pos in commentPositions.OrderByDescending(p => p.Index)) { if (pos.Index < finalLines.Count) finalLines.Insert(pos.Index, pos.Line); else finalLines.Add(pos.Line); } // 保存文件 File.WriteAllLines(configPath, finalLines); } } // 对应配置结构的模型类 public class Config { public string Name { get; set; } public string Address1 { get; set; } public string City { get; set; } public string ST { get; set; } public string Zip { get; set; } public int ItemCount { get; set; } }
其他注意事项
- 如果注释行集中在文件开头,可简化逻辑直接将注释行拼在修改后的JSON前,无需记录位置。
- 避免使用支持重复键的非标准JSON解析器:这类解析器行为不稳定,且后续维护成本高,分离注释的方案更可靠。
- 注意编码一致性:读取和保存时指定相同的编码(如UTF8),避免乱码。
内容的提问来源于stack exchange,提问作者Stephen Lee Parker
相关产品推荐
相关产品推荐

