You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET 4.8下C#提取类JSON格式文本数据的更优方案咨询

优化C# .NET 4.8下类JSON格式文本的数据提取方案

问题背景

我正在学习C#,基于.NET 4.8框架开发,需要从类JSON格式的文本文件中提取指定数据(包括主名称、关键数字、路径、分类、布尔值及嵌套列表等),最终存储到List<ClassTech>集合中。当前的逐行硬匹配解析方案在数据规模增大后,维护难度骤增,希望找到更简洁高效的实现方式。

当前实现代码

TechData = new List<ClassTech>();

string[] paths = Directory.GetFiles(path, "*.txt");

foreach (string pathsl in paths)
{
    using (StreamReader sr = File.OpenText(pathsl))
    {
        string line;
        int i = 0;
        string[] words;

        while ((line = sr.ReadLine()) != null)
        {
            if (line.Contains("{") == true && !line.Contains("#"))
            {
                // 获取名称
                words = line.Split('=');
                TechData.Add(new ClassTech(words[0].Trim(' '), "None", -1, null, "None", null, true));

                // 处理{}内的内容
                while ((line = sr.ReadLine()) != null)
                {
                    if ((Regex.Match(line, @"\bera\b")).Success && (TechData[i].era == -1) && !line.Contains("#"))
                    {
                        words = line.Split('=');
                        TechData[i].era = words[1][words[1].Length - 1] - 48;
                    }
                    else if ((Regex.Match(line, @"\btexture\b")).Success && (TechData[i].texture == null) && !line.Contains("#"))
                    {
                        words = line.Split('=');
                        TechData[i].texture = words[1].Trim(' ', '"');
                    }
                    else if ((Regex.Match(line, @"\bcategory\b")).Success && (TechData[i].category == null) && !line.Contains("#"))
                    {
                        words = line.Split('=');
                        TechData[i].category = words[1].Trim(' ');
                    }
                    else if ((Regex.Match(line, @"\bcan_research\b")).Success && (Regex.Match(line, @"\bno\b")).Success && !line.Contains("#"))
                    {
                        TechData[i].canResearch = false;
                    }
                    else if ((Regex.Match(line, @"\bmodifier\b")).Success && !line.Contains("#"))
                    {
                        while ((line = sr.ReadLine()) != null)
                        {
                            if (line.Contains("}")) { break; }
                            else if (line.Contains("="))
                            {
                                TechData[i].modifiers.Add(line.Trim(' '));
                            }
                        }
                    }
                    else if ((Regex.Match(line, @"\bunlocking_technologies\b")).Success && !line.Contains("#"))
                    {
                        while ((line = sr.ReadLine()) != null)
                        {
                            if (line.Contains("}")) { break; }
                            else if (!string.IsNullOrEmpty(line) && !string.IsNullOrWhiteSpace(line))
                            {
                                TechData[i].restrictions.Add(line.Trim('\t'));
                            }
                        }
                    }
                    else if (line.Contains("}") == true)
                    {
                        break;
                    }
                }
                i++;
            }
        }
    }
}

目标数据格式示例

sericulture = {
    # Unlocks Mulberry Groves PM on Rice Farms
    era = era_1
    texture = "gfx/interface/icons/invention_icons/sericulture.dds"
    category = production
    can_research = no
    
    modifier = {
        building_silk_plantation_throughput_mult = 0.25
        
    }
}

enclosure = {
    # Unlocks construction of Farms and Plantations
    era = era_1
    texture = "gfx/interface/icons/invention_icons/enclosure.dds"
    category = production
}

manufacturies = {
    # Unlocks Mercantilism Law
    # Unlocks Food Industry, Textile Mills, Furniture Manufacturies, Glassworks, Tooling Workshops, Paper Mills
    era = era_1
    texture = "gfx/interface/icons/invention_icons/manufacturies.dds"
    category = production
}

shaft_mining = {
    # Unlocks Coal Mine, Iron Mine, Lead Mine, Sulfur Mine
    era = era_1
    texture = "gfx/interface/icons/invention_icons/shaft_mining.dds"
    category = production
    
    unlocking_technologies = {
        enclosure
        manufacturies
    }
}

atmospheric_engine = {
    # Unlocks Motor Industry
    # Unlocks Atmospheric Engine Pump PM in Coal Mine, Iron Mine, Lead Mine, Sulfur Mine
    era = era_1
    texture = "gfx/interface/icons/invention_icons/atmospheric_engine.dds"
    category = production
    
    unlocking_technologies = {
        shaft_mining
    }
}

优化实现方案

当前逐行硬匹配的代码扩展性极差,推荐两种更高效的思路:

方案1:利用现成的PDX脚本解析库

你处理的是Paradox游戏常用的PDX脚本格式,已有成熟的.NET解析库支持(适配.NET 4.8),这类库可以直接将文本解析为结构化对象,无需手动处理每一行。核心步骤:

  1. 引入适配.NET Framework的PDX脚本解析NuGet包
  2. 读取文本文件内容
  3. 调用库的解析方法将文本转为动态对象或强类型模型
  4. 直接映射到ClassTech集合

这种方式完全省去手动解析的繁琐,后续新增字段也无需修改解析逻辑。

方案2:自定义模块化解析器

如果不想依赖第三方库,可以将解析逻辑拆分为三个独立模块,降低维护成本:

1. 文本预处理模块

先清理掉注释、空白行,统一格式:

private static IEnumerable<string> PreprocessLines(string filePath)
{
    return File.ReadLines(filePath)
        .Select(line => line.Trim())
        .Where(line => !string.IsNullOrWhiteSpace(line) && !line.StartsWith("#"));
}

2. 递归解析模块

通过递归识别嵌套块,将整个文本解析为键值对字典:

private static Dictionary<string, object> ParseBlock(IEnumerator<string> lineEnumerator)
{
    var block = new Dictionary<string, object>();
    while (lineEnumerator.MoveNext())
    {
        var line = lineEnumerator.Current;
        if (line == "}")
            break;
            
        if (line.Contains("="))
        {
            var parts = line.Split(new[] { '=' }, 2);
            var key = parts[0].Trim();
            var valuePart = parts[1].Trim();
            
            if (valuePart == "{")
            {
                // 递归解析嵌套块
                block[key] = ParseBlock(lineEnumerator);
            }
            else
            {
                // 处理普通值,去掉引号
                block[key] = valuePart.Trim('"');
            }
        }
        else
        {
            // 处理无值的项(比如unlocking_technologies里的条目)
            if (block.TryGetValue("__items", out var itemsObj) && itemsObj is List<string> items)
            {
                items.Add(line);
            }
            else
            {
                block["__items"] = new List<string> { line };
            }
        }
    }
    return block;
}

// 顶级解析方法
private static List<Dictionary<string, object>> ParseTechFiles(string directoryPath)
{
    var techBlocks = new List<Dictionary<string, object>>();
    foreach (var filePath in Directory.GetFiles(directoryPath, "*.txt"))
    {
        var lines = PreprocessLines(filePath).GetEnumerator();
        while (lines.MoveNext())
        {
            var line = lines.Current;
            if (line.Contains("=") && line.EndsWith("{"))
            {
                var parts = line.Split(new[] { '=' }, 2);
                var techName = parts[0].Trim();
                var techBlock = ParseBlock(lines);
                techBlock["Main_name"] = techName;
                techBlocks.Add(techBlock);
            }
        }
    }
    return techBlocks;
}

3. 模型映射模块

将解析后的字典映射到ClassTech对象:

private static List<ClassTech> MapToClassTech(List<Dictionary<string, object>> techBlocks)
{
    var techList = new List<ClassTech>();
    foreach (var block in techBlocks)
    {
        var tech = new ClassTech
        {
            Main_name = block["Main_name"].ToString(),
            era = int.Parse(block["era"].ToString().Split('_')[1]),
            texture = block["texture"].ToString(),
            category = block["category"].ToString(),
            canResearch = !block.ContainsKey("can_research") || block["can_research"].ToString() != "no",
            modifiers = block.ContainsKey("modifier") && block["modifier"] is Dictionary<string, object> modifierBlock 
                ? modifierBlock.Keys.Select(k => $"{k} = {modifierBlock[k]}").ToList() 
                : new List<string>(),
            restrictions = block.ContainsKey("unlocking_technologies") && block["unlocking_technologies"] is Dictionary<string, object> unlockBlock 
                ? unlockBlock["__items"] as List<string> 
                : new List<string>()
        };
        techList.Add(tech);
    }
    return techList;
}

使用方式

var parsedBlocks = ParseTechFiles("你的目录路径");
TechData = MapToClassTech(parsedBlocks);

这种模块化的方式,后续新增字段只需要修改映射逻辑,解析逻辑无需改动,维护成本大幅降低。


内容的提问来源于stack exchange,提问作者Filipe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 00:15:41