从没有第三方的文本文件中解析函数

时间:2018-03-06 10:20:08

标签: c# parsing

我一直在努力围绕解析器和词法分析器,我甚至不确定这是解决我的挑战的最佳方法。我不想使用任何第三方库,因为不必要的开销,项目大小和可能的许可证问题。 也不会有任何算术,循环,而对于或者是foreach的 它是一个非常简单的解析器,可以从文本文件中添加或实例化对象。 例如,

buildings.addWithMaterials([buildable:mansion], {{[materials: brick], [materials: wood]}, {[materials: wood], [materials: brick]}});

解析这个文本会在建筑物集合中添加一块由两块砖木制成的大厦。 对象可构建包含属性Name,在本例中为Mansion 和一些建筑构件,在这种情况下是砖和木材料。 任何提示/方向搜索这样做? 我在stackoverflow中查看并搜索过,我偶然发现的大多数条目都是指第三方 像Sprache等等。

如果我错过了一篇文章,那么:/抱歉,请指出我

谢谢和亲切的问候,尼克

1 个答案:

答案 0 :(得分:0)

提供脚本中的所有项目都采用相同的格式,您可以使用类似的内容来解析它:

public static class ScriptParser
{
    public static void Parse(string filename)
    {
        string[] script = null;
        using (StreamReader reader = File.OpenText(filename))
        {
            // read the whole file, remove all line breaks and split 
            // by semicolons to get individual commands
            script = reader.ReadToEnd().Replace("\r", string.Empty.Replace("\n", string.Empty)).Split(';');
        }
        foreach (string command in script)
            HandleCommand(command);
    }
    // as arguments seem to be grouped you can't just split
    // by commas so this will get the arguments recursively
    private static object[] ParseArgs(string argsString)
    {
        int startPos = 0;
        int depth = 0;
        List<object> args = new List<object>();
        Action<int> addArg = pos =>
        {
            string arg = argsString.Substring(startPos, pos - startPos).Trim();
            if (arg.StartsWith("{") && arg.EndsWith("}"))
            {
                arg = arg.Substring(1, arg.Length - 2);
                args.Add(ParseArgs(arg));
            }
            else
            {
                args.Add(arg);
            }
        }
        for (int i = 0; i < argsString.Length; i++)
        {
            switch (argsString[i])
            {
                case ',':
                    if (depth == 0)
                    {
                        addArg(i);
                        startPos = i + 1;
                    }
                    break;
                case '{':
                    // increase depth of parsing so that commas
                    // within braces are ignored
                    depth++;
                    break;
                case '}':
                    // decrease depth when exiting braces
                    depth--;
                    break;
            }
        }
        // as there is no final comma
        addArg(argsString.Length);
        return args.ToArray();
    }
    private static void HandleCommand(string commandString)
    {
        Command command = new Command();
        string prefix = commandString.Substring(0, commandString.IndexOf("("));
        command.Collection = prefix.Split('.')[0];
        command.Action = prefix.Split('.')[1];

        string commandArgs = commandString.Substring(commandString.IndexOf("("));
        commandArgs = commandArgs.Substring(1, commandArgs.Length - 2);

        command.Args = ParseArgs(commandArgs);
        command.Execute();
    }
    private class Command
    {
        public string Collection;
        public string Action;
        public object[] Args;
        public void Execute()
        {
            // need to handle any expected commands
            if (Collection == "buildings")
            {
                if (Action == "addWithMaterials")
                {
                    buildings.AddWithMaterials((string)Args[0], (object[])Args[1]);
                }
            }
        }
    }

    //Eg.
    public static BuildingCollection buildings = new BuildingCollection();
    public class BuildingCollection
    {
        public void AddWithMaterials(string building, object[] materials)
        {
            Building building = new Building();
            foreach (object[] materialsPart in materials)
                // more stuff for you to work out
                // you will need to match the strings to material classes
        }
    }
}

用法:

ScriptParser.Parse("scriptfile.txt");

注意:这缺少错误处理,在解析文件时您肯定需要它,因为它可能包含任何内容。