从C#中的嵌套支架解析数据

发布于 2025-02-03 13:17:43 字数 12223 浏览 3 评论 0原文

终于在制作了许多遇到同样错误的解析器之后,我自己解决了这个问题。 工作(清洁剂但仍然需要更多清洁)代码在这里

if(input> 47& lt; 123) 如果(输入> 44& input< 123)包括“”。 感谢您没有帮助。

修改 this 示例代码几乎对我有用,并且是了解更多信息的起点。

我一直在尝试解析Game Europa Universalis IV中的一些文件。 文件包含类似的文本:

示例2

in案例某人想帮助调试在这里是一个浏览器版本,有2个处理的外部设备。

一旦一切工作,每个对象都完成后,数据将被放入数据库中。为了进行测试,我只是将进度写入文本文件。

我以不同的方式尝试了几次,几乎总是看起来一样。到现在为止,该过程已分为部分,其中大多数工作起作用。

我首先收集每个游戏文件中的所有“外部”(第一级括号)(仅用于快速测试),此步骤很容易。 我将这些外部实体放入游戏文件对象中的列表中(ToString覆盖仅用于测试):

gamefile

 internal record GameFile
{
    public List<string> UnprocessedOuterEntites = new();
    public string Name;
    public string Path;
    public List<OuterEntity> OuterEntities = new();
    public override string ToString()
    {
        StringBuilder sb = new();
        sb.AppendLine(Name);
        sb.AppendLine(Path);
        foreach(OuterEntity entity in OuterEntities)
        {
            sb.AppendLine(entity.ToString());
        }
        foreach(string entity in UnprocessedOuterEntites)
        {
            sb.AppendLine(entity);
        }
        return sb.ToString();
    }

exustentity

internal class OuterEntity
{
    public List<string> UnprocessedInnerEntities = new();
    public string? Name = "";
    public List<InnerEntity> InnerEntities = new();
    public void Clear()
    {
        this.UnprocessedInnerEntities.Clear();
        this.InnerEntities.Clear();
        this.Name = null;
    }
    public override string ToString()
    {
        StringBuilder sb = new();
        sb.Append(Name);
        foreach (InnerEntity entity in InnerEntities)
        {
            sb.Append(entity.ToString());
        }
        foreach(string entity in UnprocessedInnerEntities)
        {
            sb.Append(entity);
        }
        return sb.ToString();
    }
}

这些外部体内包含内在物质,其中包含价值或更多的内在性(嵌套嵌套括号):

内实体

internal class InnerEntity
{
    public List<string> UnprocessedInnerEntities = new();
    public string? Name;
    public string? Value;
    public List<InnerEntity> InnerEntities = new();
    public void Clear()
    {
        this.Name = null;
        this.Value = null;
        this.InnerEntities = new();
        this.UnprocessedInnerEntities = new();
    }
    public override string ToString()
    {
        StringBuilder sb = new StringBuilder();
        sb.AppendLine(Name);
        if (InnerEntities.Count > 0)
        {
            foreach (InnerEntity entity in InnerEntities)
            {
                sb.Append(entity.ToString());
            }
        }
        else
        {
            sb.AppendLine(Value);
        }
        foreach (string String in UnprocessedInnerEntities)
        {
            sb.AppendLine(String);
        }
        return sb.ToString();
    }

该程序(用于测试)像这样运行:

internal class Program{
private static Program program = new();
public List<GameFile> gameFiles = new();
public static void Main()
{
    program.Run();
}
private void Run()
{
    string[] paths = Directory.GetFiles("Source", "*.txt", SearchOption.AllDirectories);
    foreach (string path in paths)
    {
        Process.GetOuterEntities(path,this);
    }
    Process.ProcessOuterEntities(this);
    Process.ProcessInnerEntities(this);
    Test.PrintOuterEntities(this);
}}

收集和处理外观:

public static void GetOuterEntities(string path, Program program)
    {
        string[] lines = System.IO.File.ReadAllLines(path);
        GameFile file = new GameFile() { Path = path };
        StringBuilder sb = new StringBuilder();
        int currentPos = 0;
        int lastPos = 0;
        int brackets = 0;
        bool inBrackets = false;
        string st = RemoveComments(lines);
        OuterEntity entity = new OuterEntity();
        foreach (char c in st)
        {
            if (c == '{')
            {
                inBrackets = true;
                brackets++;
            }
            else if (c == '}')
            {
                brackets--;
            }
            if (brackets == 0 && inBrackets)//End Outer
            {
                sb.Clear();
                inBrackets = false;
                for (int i = lastPos; i <= currentPos; i++)
                {
                    if (st[i] != '\n')
                    {
                        sb.Append(st[i]);
                    }
                }
                file.UnprocessedOuterEntites.Add(sb.ToString());
                program.gameFiles.Add(file);
                lastPos = currentPos + 1;
            }
            currentPos++;
        }

 public static void ProcessOuterEntities(Program program)
    {
        foreach (GameFile file in program.gameFiles)
        {
            foreach (string UnprocessedOuterEntity in file.UnprocessedOuterEntites)
            {
                file.OuterEntities.Add(ProcessOuterEntity(UnprocessedOuterEntity));
            }
            file.UnprocessedOuterEntites.Clear();
        }
    }


private static OuterEntity ProcessOuterEntity(string UnprocessedOuterEntity)
    {
        OuterEntity processedOuterEntity = new();
        int currentPos = 0;
        int lastPos = 0;
        int brackets = 0;
        bool inBrackets = false;
        StringBuilder sb = new StringBuilder();
        foreach (char c in UnprocessedOuterEntity)
        {
            if (c == '{')
            {
                if (processedOuterEntity.Name == "")
                {
                    for (int i = lastPos; i <= currentPos; i++)
                    {
                        if (UnprocessedOuterEntity[i] != '\n')
                        {
                            sb.Append(UnprocessedOuterEntity[i]);
                        }
                    }
                    processedOuterEntity.Name = sb.ToString();
                    sb.Clear();
                    lastPos = currentPos + 1;
                }
                inBrackets = true;
                brackets++;
            }
            else if (c == '}')
            {
                brackets--;
            }
            if (brackets == 0 && inBrackets)
            {
                inBrackets = false;
                for (int i = lastPos; i <= currentPos; i++)
                {
                    sb.Append(UnprocessedOuterEntity[i]);
                }
                processedOuterEntity.UnprocessedInnerEntities.Add(sb.ToString());
                sb.Clear();
                lastPos = currentPos + 1;
            }
            currentPos++;
        }
        return processedOuterEntity;
    }

在此之后,我未能处理内部实体。

这是当前不起作用的部分:

 private static InnerEntity ProcessInnerEntity(string UnprocessedInnerEntity, bool WaitingForValue = false)
    {
        InnerEntity processedInnerEntity = new();
        int currentPos = 0;
        int lastPos = 0;
        int brackets = 0;
        bool inBrackets = false;
        bool waitingForValue = WaitingForValue;
        StringBuilder sb = new StringBuilder();
        foreach (char c in UnprocessedInnerEntity)
        {
           
            if (c == '{')//Brackets opening
            {
                inBrackets = true;
                brackets++;
            }
            else if (c == '}')//Brackets closing
            {
                brackets--;
            }
            else if (c == '=')//Name behind, Value or NestedEntity in front
            {
                for (int i = lastPos; i <= currentPos; i++)
                {
                    sb.Append(UnprocessedInnerEntity[i]);
                }
                processedInnerEntity.Name = sb.ToString();
                sb.Clear();
                lastPos = currentPos + 1;
                waitingForValue = true;
                if (inBrackets)//In a nested bracket, find InnerEntity
                {
                    processedInnerEntity.InnerEntities.Add(ProcessInnerEntity(UnprocessedInnerEntity.Substring(currentPos + 1), waitingForValue));//Search everything in front
                }
            }
            else if (c<47 | c > 123)//Not text
            {
                if (waitingForValue)//After =
                {
                    for (int i = lastPos; i <= currentPos; i++)
                    {
                        if (c > 47 & c < 123)//Text
                        {
                            waitingForValue = false;
                            sb.Append(UnprocessedInnerEntity[i]); 
                        }
                    }
                    if (!waitingForValue)//Has value
                    {
                        processedInnerEntity.Value = sb.ToString();
                        sb.Clear();
                    }
                }
            }
            if (brackets == 0 && inBrackets)//Brackets closed
            {
                inBrackets = false;
                currentPos++;
                break;
            }
            currentPos++;
        }
        return processedInnerEntity;
    }

可以找到其余的代码在这里

调试文件像这样写了

 internal class Test
{
    public static void PrintOuterEntities(Program program)
    {
        List<string> strings = new();
        foreach (GameFile gameFile in program.gameFiles)
        {
            strings.Add(gameFile.ToString());
        }
        foreach (string String in strings)
        {
            File.WriteAllText("test.txt", String);
        }
    }
}

当前输出看起来像这样:

source\common\ideas\00_country_ideas.txt
HLR_ideas = { 1     diplomatic_reputation =
 2  }       bonus =

 2  }       bonus =


GER_ideas = { 0.3       infantry_power =
 0.15   }       bonus =

 0.15   }       bonus =

 0.15   }       bonus =

 0.15   }       bonus =

我想要一个包含其内在性的外部列表:

OuterEntity //Object
Name HLR_Ideas
InnerEntities //List
    Name start
        InnerEntities 
            Name possible_policy
                Value 1
            Name diplomatic_reputation
                Value 2
    Name bonus
        InnerEntities
            Name administrative_efficiency
                Value 0.05
    Name trigger
        InnerEntities
            Name tag
                Value HLR
    Name free
        Value yes
    Name hlr_imperial_throne
        InnerEntities
            Name legitimacy
                Value 1.5
    Name hlr_kaiserliche_armee
        InnerEntities
            Name land_morale
                Value 0.15
    Name hlr_imperial_diplomacy
        InnerEntities
            Name improve_relation_modifier
                Value 0.33
    Name hlr_centralised_empire
        InnerEntities
            Name global_tax_modifier 
                Value 0.2
    Name hlr_roman_heritage 
        InnerEntities
            Name core_creation 
                Value -0.2
    Name hlr_adopting_the_goosestep 
        InnerEntities
            Name discipline
                Value 0.05
    Name hlr_onwards_and_upwards 
        InnerEntities
            Name governing_capacity_modifier 
                Value 0.1
            
            

是否有东西很明显我在最后一部分做错了吗?我不知道我想重塑的车轮吗?我只是学习perl还是我在那里看到的奇特的非正则表达式?

Finally solved this myself after making many styles of parsers suffering from the same bug...
Working (cleaner but still needs more cleaning) code Here

if(input > 47 & input < 123) should be
if(input > 44 & input < 123) to include the '.'
thanks for no help.

Modifying This example code almost works for me, and is a starting point to learn more.

I've been trying to parse some files from the game Europa Universalis IV.
The files contain text like this:

Example 1

Example 2

In case someone wants to help debug Here is a browser version with 2 processed OuterEntities as example.

Once everything works the data would be put into a database after every object is finished. For testing I just write my progress to a text file.

I have tried this a couple times in different ways that almost always end up looking the same. By now the process is split into parts, and most of them work.

I start by collecting all the "OuterEntities" (First level brackets) in each of the GameFiles (just one for fast testing), this step is easy.
I put those outer entities into a list in a GameFile object (ToString overrides are just for testing) :

GameFile

 internal record GameFile
{
    public List<string> UnprocessedOuterEntites = new();
    public string Name;
    public string Path;
    public List<OuterEntity> OuterEntities = new();
    public override string ToString()
    {
        StringBuilder sb = new();
        sb.AppendLine(Name);
        sb.AppendLine(Path);
        foreach(OuterEntity entity in OuterEntities)
        {
            sb.AppendLine(entity.ToString());
        }
        foreach(string entity in UnprocessedOuterEntites)
        {
            sb.AppendLine(entity);
        }
        return sb.ToString();
    }

OuterEntity

internal class OuterEntity
{
    public List<string> UnprocessedInnerEntities = new();
    public string? Name = "";
    public List<InnerEntity> InnerEntities = new();
    public void Clear()
    {
        this.UnprocessedInnerEntities.Clear();
        this.InnerEntities.Clear();
        this.Name = null;
    }
    public override string ToString()
    {
        StringBuilder sb = new();
        sb.Append(Name);
        foreach (InnerEntity entity in InnerEntities)
        {
            sb.Append(entity.ToString());
        }
        foreach(string entity in UnprocessedInnerEntities)
        {
            sb.Append(entity);
        }
        return sb.ToString();
    }
}

Those OuterEntities contain InnerEntities, which contain values or more InnerEntities (Nested brackets) :

Inner Entity

internal class InnerEntity
{
    public List<string> UnprocessedInnerEntities = new();
    public string? Name;
    public string? Value;
    public List<InnerEntity> InnerEntities = new();
    public void Clear()
    {
        this.Name = null;
        this.Value = null;
        this.InnerEntities = new();
        this.UnprocessedInnerEntities = new();
    }
    public override string ToString()
    {
        StringBuilder sb = new StringBuilder();
        sb.AppendLine(Name);
        if (InnerEntities.Count > 0)
        {
            foreach (InnerEntity entity in InnerEntities)
            {
                sb.Append(entity.ToString());
            }
        }
        else
        {
            sb.AppendLine(Value);
        }
        foreach (string String in UnprocessedInnerEntities)
        {
            sb.AppendLine(String);
        }
        return sb.ToString();
    }

The program is (for testing) run like this:

internal class Program{
private static Program program = new();
public List<GameFile> gameFiles = new();
public static void Main()
{
    program.Run();
}
private void Run()
{
    string[] paths = Directory.GetFiles("Source", "*.txt", SearchOption.AllDirectories);
    foreach (string path in paths)
    {
        Process.GetOuterEntities(path,this);
    }
    Process.ProcessOuterEntities(this);
    Process.ProcessInnerEntities(this);
    Test.PrintOuterEntities(this);
}}

The OuterEntities are collected and processed:

public static void GetOuterEntities(string path, Program program)
    {
        string[] lines = System.IO.File.ReadAllLines(path);
        GameFile file = new GameFile() { Path = path };
        StringBuilder sb = new StringBuilder();
        int currentPos = 0;
        int lastPos = 0;
        int brackets = 0;
        bool inBrackets = false;
        string st = RemoveComments(lines);
        OuterEntity entity = new OuterEntity();
        foreach (char c in st)
        {
            if (c == '{')
            {
                inBrackets = true;
                brackets++;
            }
            else if (c == '}')
            {
                brackets--;
            }
            if (brackets == 0 && inBrackets)//End Outer
            {
                sb.Clear();
                inBrackets = false;
                for (int i = lastPos; i <= currentPos; i++)
                {
                    if (st[i] != '\n')
                    {
                        sb.Append(st[i]);
                    }
                }
                file.UnprocessedOuterEntites.Add(sb.ToString());
                program.gameFiles.Add(file);
                lastPos = currentPos + 1;
            }
            currentPos++;
        }

 public static void ProcessOuterEntities(Program program)
    {
        foreach (GameFile file in program.gameFiles)
        {
            foreach (string UnprocessedOuterEntity in file.UnprocessedOuterEntites)
            {
                file.OuterEntities.Add(ProcessOuterEntity(UnprocessedOuterEntity));
            }
            file.UnprocessedOuterEntites.Clear();
        }
    }


private static OuterEntity ProcessOuterEntity(string UnprocessedOuterEntity)
    {
        OuterEntity processedOuterEntity = new();
        int currentPos = 0;
        int lastPos = 0;
        int brackets = 0;
        bool inBrackets = false;
        StringBuilder sb = new StringBuilder();
        foreach (char c in UnprocessedOuterEntity)
        {
            if (c == '{')
            {
                if (processedOuterEntity.Name == "")
                {
                    for (int i = lastPos; i <= currentPos; i++)
                    {
                        if (UnprocessedOuterEntity[i] != '\n')
                        {
                            sb.Append(UnprocessedOuterEntity[i]);
                        }
                    }
                    processedOuterEntity.Name = sb.ToString();
                    sb.Clear();
                    lastPos = currentPos + 1;
                }
                inBrackets = true;
                brackets++;
            }
            else if (c == '}')
            {
                brackets--;
            }
            if (brackets == 0 && inBrackets)
            {
                inBrackets = false;
                for (int i = lastPos; i <= currentPos; i++)
                {
                    sb.Append(UnprocessedOuterEntity[i]);
                }
                processedOuterEntity.UnprocessedInnerEntities.Add(sb.ToString());
                sb.Clear();
                lastPos = currentPos + 1;
            }
            currentPos++;
        }
        return processedOuterEntity;
    }

After this I fail to process the inner entities.

This is the currently not working part:

 private static InnerEntity ProcessInnerEntity(string UnprocessedInnerEntity, bool WaitingForValue = false)
    {
        InnerEntity processedInnerEntity = new();
        int currentPos = 0;
        int lastPos = 0;
        int brackets = 0;
        bool inBrackets = false;
        bool waitingForValue = WaitingForValue;
        StringBuilder sb = new StringBuilder();
        foreach (char c in UnprocessedInnerEntity)
        {
           
            if (c == '{')//Brackets opening
            {
                inBrackets = true;
                brackets++;
            }
            else if (c == '}')//Brackets closing
            {
                brackets--;
            }
            else if (c == '=')//Name behind, Value or NestedEntity in front
            {
                for (int i = lastPos; i <= currentPos; i++)
                {
                    sb.Append(UnprocessedInnerEntity[i]);
                }
                processedInnerEntity.Name = sb.ToString();
                sb.Clear();
                lastPos = currentPos + 1;
                waitingForValue = true;
                if (inBrackets)//In a nested bracket, find InnerEntity
                {
                    processedInnerEntity.InnerEntities.Add(ProcessInnerEntity(UnprocessedInnerEntity.Substring(currentPos + 1), waitingForValue));//Search everything in front
                }
            }
            else if (c<47 | c > 123)//Not text
            {
                if (waitingForValue)//After =
                {
                    for (int i = lastPos; i <= currentPos; i++)
                    {
                        if (c > 47 & c < 123)//Text
                        {
                            waitingForValue = false;
                            sb.Append(UnprocessedInnerEntity[i]); 
                        }
                    }
                    if (!waitingForValue)//Has value
                    {
                        processedInnerEntity.Value = sb.ToString();
                        sb.Clear();
                    }
                }
            }
            if (brackets == 0 && inBrackets)//Brackets closed
            {
                inBrackets = false;
                currentPos++;
                break;
            }
            currentPos++;
        }
        return processedInnerEntity;
    }

The rest of the code can be found here

The debug file is written like this

 internal class Test
{
    public static void PrintOuterEntities(Program program)
    {
        List<string> strings = new();
        foreach (GameFile gameFile in program.gameFiles)
        {
            strings.Add(gameFile.ToString());
        }
        foreach (string String in strings)
        {
            File.WriteAllText("test.txt", String);
        }
    }
}

Current output looks like this:

source\common\ideas\00_country_ideas.txt
HLR_ideas = { 1     diplomatic_reputation =
 2  }       bonus =

 2  }       bonus =


GER_ideas = { 0.3       infantry_power =
 0.15   }       bonus =

 0.15   }       bonus =

 0.15   }       bonus =

 0.15   }       bonus =

I want a list of OuterEntities containing their InnerEntities like this:

OuterEntity //Object
Name HLR_Ideas
InnerEntities //List
    Name start
        InnerEntities 
            Name possible_policy
                Value 1
            Name diplomatic_reputation
                Value 2
    Name bonus
        InnerEntities
            Name administrative_efficiency
                Value 0.05
    Name trigger
        InnerEntities
            Name tag
                Value HLR
    Name free
        Value yes
    Name hlr_imperial_throne
        InnerEntities
            Name legitimacy
                Value 1.5
    Name hlr_kaiserliche_armee
        InnerEntities
            Name land_morale
                Value 0.15
    Name hlr_imperial_diplomacy
        InnerEntities
            Name improve_relation_modifier
                Value 0.33
    Name hlr_centralised_empire
        InnerEntities
            Name global_tax_modifier 
                Value 0.2
    Name hlr_roman_heritage 
        InnerEntities
            Name core_creation 
                Value -0.2
    Name hlr_adopting_the_goosestep 
        InnerEntities
            Name discipline
                Value 0.05
    Name hlr_onwards_and_upwards 
        InnerEntities
            Name governing_capacity_modifier 
                Value 0.1
            
            

Is there something obvious I'm doing wrong in the last part? Are there existing wheels I don't know about I'm trying to reinvent? Do I just learn Perl or the fancy non regular regular expressions I see out there?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文