简体   繁体   English

从模板文件加载文本

[英]Loading text from template file

Currently I have a lot of strings in an array that can be filled with all kinds of data. 目前,我在array中有很多strings ,可以填充各种数据。 An example: 一个例子:

var obj = new Example();    
var test = new Test();

// This must be stored in a text file
var text = new[] {
    $"{obj} contains {obj.attribute}",
    $"This is a {test.title}"
}

foreach (var line in text)
    Console.WriteLine(line);

As you see, this text array is filled with different strings, which contain external data (for example, data from the obj and test objects). 如您所见,此文text数组填充了不同的字符串,其中包含外部数据(例如,来自objtest对象的数据)。


My question: The goal is to read lines of text from a .txt file and load them into the text variable, so the result will be the same as above. 我的问题:目标是从.txt file读取text行并将其加载到text变量中,因此结果将与上述相同。

The only condition is that this text file must include all the 'variables', like obj and test.title , so it will print the correct data contained in these objects. 唯一的条件是该文本文件必须包含所有“变量”,例如objtest.title ,因此它将打印出这些对象中包含的正确数据。 How do I store these lines in a .txt file and load them into the application? 如何将这些行存储在.txt file并将它们加载到应用程序中?

You will nedd create Placeholders 您将需要创建占位符

In file will have lines: 在文件中将包含以下行:

${obj} contains ${obj.attribute}
This is a ${test.title}"

Placeholders are ${....} 占位符为$ {....}

Then You will need parse file, line by line. 然后,您将需要逐行解析文件。

You resolve the placeholders. 您解析占位符。

In placeholders first part of string is name of object. 在占位符中,字符串的第一部分是对象名称。

Therefore you will need to have mapper of existings object in program to object in file. 因此,您将需要在程序中将存在对象的映射器映射到文件中的对象。

Then, You create container with that mapper 然后,使用该映射器创建容器

Then you are map the object from file to object from container and using reflection you get the vale of what You define in placeholder 然后,您将对象从文件映射到容器中的对象,并使用反射获得关于您在占位符中定义的内容的信息

Another way: 其他方式:

You have only placeholders and mapper. 您只有占位符和映射器。

In file: 在文件中:

${obj} contains ${obj.attribute}
    This is a ${test.title}"

Mapper (for example dictionary) 映射器(例如字典)

  var fileMapper = new Dictionary<string, string>
                    {
                        ["obj"] = "sfsfs",
                        ["obj.attribute"] = "sfsfs"
                    };

And now you need to get placeholders and replace with object form dictionary. 现在,您需要获取占位符并替换为对象表单字典。

Reflection is not nessesery 反思不是必要

Full working example (compiled and tested) 完整的工作示例(经过编译和测试)

class Example
    {
        public void GetFile()
        {
            var fileMapper = new Dictionary<string, string>
            {
                ["obj"] = "sfsfs",
                ["obj.attribute"] = "sfsfs"
            };

            var fileLines = new List<string>();

            using (var sr = new StreamReader("FileName"))
            {
                var line = string.Empty;

                while ((line = sr.ReadLine()) != null)
                {
                    List<string> listOfPlaceHolders = this.GetPlaceHolders(line);

                    for (var i = 0; i < listOfPlaceHolders.Count; i++)
                    {
                        line = line.Replace("${" + listOfPlaceHolders[i] + "}", fileMapper[listOfPlaceHolders[i]]);
                    }

                    fileLines.Add(line);
                }
            }


            foreach (var line in fileLines)
            {
                Console.WriteLine(line);
            }
        }

        public List<string> GetPlaceHolders(string line)
        {
            var result = new List<string>();

            var placeHoldersIndex = new List<int>();

            var open = false;

            for (var i = 0; i < line.Length; i++)
            {
                if (line[i] == '{' && !open)
                {
                    open = true;
                    placeHoldersIndex.Add(i+1);
                }

                if (line[i] == '}' && open)
                {
                    placeHoldersIndex.Add(i);
                    open = false;
                }
            }

            for (var j = 0; j < placeHoldersIndex.Count(); j += 2)
            {
               result.Add(line.Substring(placeHoldersIndex[j], placeHoldersIndex[j+1] - placeHoldersIndex[j]));
            };

            return result;
        }

    }

Here is a possible solution (compiled, but not tested): 这是一个可能的解决方案(已编译,但未经测试):

Declare a class like this: 声明一个这样的类:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;


namespace ConsoleApplication1 {
    public class TemplateParser {

        private string content;

        public TemplateParser(string fileName) {
            Tags = new Dictionary<string, object>();
            //TODO: Add exception control. Perhaps move the reading operation outside the constructor
            content = File.ReadAllText(fileName);
        }

        public Dictionary<string, object> Tags { get; private set; }

        public void Parse() {
            foreach (string key in Tags.Keys) {
                if (Tags[key] != null) {
                object propertyValue;
                int position = key.IndexOf('.');
                if (position >= 0) {
                    string propertyName = key.Substring(position + 1);
                    propertyValue = GetPropertyValue(Tags[key], propertyName);
                } else {
                    propertyValue = Tags[key];
                }
                content = content.Replace(string.Concat("{", key, "}"), propertyValue.ToString());
                } else {
                    //TODO: what to do without not specified replacement?
                }
            }
        }

        public string[] ToArray() {
            return content.Split(new string[] {Environment.NewLine}, StringSplitOptions.RemoveEmptyEntries);
        }


        private object GetPropertyValue(object obj, string propertyName) {
            PropertyInfo pi = obj.GetType().GetProperties().FirstOrDefault(x => x.Name == propertyName);
            if (pi != null) {
                return pi.GetValue(obj, null);
            }
            return null;
        }

    }
}

Usage: 用法:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1 {
    class Program {
        static void Main(string[] args) {
            TemplateParser parser = new TemplateParser("C:\\myTextFile.txt");
            parser.Tags.Add("obj", 1);
            parser.Tags.Add("Test", new Test { Id = 1, Title = "This is a text" });

            parser.Parse();
            foreach (string line in parser.ToArray()) {
                Console.WriteLine(line);
            }
        }
    }

    class Test {
        public int Id { get; set; }
        public string Title { get; set; }
    }
}

Based on mnieto's answer I have been able to build an actual solution to my problem: 根据mnieto的回答,我已经能够为我的问题建立一个实际的解决方案:

public class TemplateParser
{
    private string _content;
    public Dictionary<string, object> Variables { get; } = new Dictionary<string, object>();

    public TemplateParser(string filepath)
    {
        try
        {
            _content = File.ReadAllText(filepath);
        }
        catch (IOException)
        {
            Console.WriteLine("File could not be found on the following location:\n" + filepath);
        }
    }

    public void Parse()
    {
        var placeholder = "";
        var beginIndex = 0;
        var busy = false;

        for (var i = 0; i < _content.Length; i++)
            switch (_content[i])
            {
                case '{':
                    placeholder = "";
                    busy = true;
                    beginIndex = i;

                    break;
                case '}':
                    if (placeholder != "")
                    {
                        var position = placeholder.IndexOf('.');
                        var success = false;

                        try
                        {
                            object pValue;
                            if (position >= 0)
                            {
                                var pName = placeholder.Substring(position + 1);
                                pValue = GetPropertyValue(Variables[placeholder.Substring(0, position)], pName);
                            }
                            else pValue = Variables[placeholder];

                            if (pValue == null)
                            {
                                Console.WriteLine("Property not found");
                                throw new KeyNotFoundException("Property not found");
                            }

                            _content = _content.Replace("{" + placeholder + "}", pValue.ToString());
                            success = true;
                        }
                        catch (KeyNotFoundException)
                        {
                            Console.WriteLine("WARNING: Placeholder {" + placeholder + "} is unknown");
                            _content = _content.Replace("{" + placeholder + "}", "x");
                        }

                        busy = false;
                        if (success) i = beginIndex;
                    }

                    break;
                default:
                    if (busy) placeholder += _content[i];
                    break;
            }
    }

    private static object GetPropertyValue(object obj, string propertyName)
    {
        var pi = obj.GetType().GetProperties().FirstOrDefault(x => x.Name == propertyName);

        FieldInfo fi = null;
        if (pi == null)
            foreach (var x in obj.GetType().GetFields().Where(x => x.Name == propertyName))
            {
                fi = x;
                break;
            }

        return pi != null ? pi.GetValue(obj) : fi?.GetValue(obj);
    }

    public string[] ToArray() => _content.Split(new[] {Environment.NewLine}, StringSplitOptions.RemoveEmptyEntries);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM