【问题标题】:Loading text from template file从模板文件加载文本
【发布时间】:2016-01-20 14:44:41
【问题描述】:

目前我在array 中有很多strings,可以填充各种数据。一个例子:

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);

如您所见,这个text 数组填充了不同的字符串,其中包含外部数据(例如,来自objtest 对象的数据)。


我的问题: 目标是从.txt file 中读取text 的行并将它们加载到text 变量中,因此结果将与上面相同。

唯一的条件是该文本文件必须包含所有“变量”,例如objtest.title,因此它将打印这些对象中包含的正确数据。如何将这些行存储在 .txt file 中并将它们加载到应用程序中?

【问题讨论】:

  • 我不清楚您要完成什么。或者字符串数组现在是什么样子,读取文件后应该是什么样子。此外,您应该知道文件 I/O 是一个相当广泛的主题,因此您应该有一个特定的问题,而不是“什么是最好的方法”
  • @ryanyuyu 我已经尝试改进这个问题,希望现在很清楚
  • 您需要文字字符串"{obj}" 还是您实际上必须解析文本文件并获取obj 的实际值?目前还不清楚。在文件中存储数据有很多更好的方法。 XML 是一种体面的人类可读的数据存储方式。
  • @ryanyuyu 例如,如果我有一个对象obj,其属性为test。我需要能够将{obj.test} 放入字符串中,所以它将被test 的值替换,可以是任何随机字符串。

标签: c# arrays file text


【解决方案1】:

这是一个可能的解决方案(已编译,但未经测试):

像这样声明一个类:

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;
        }

    }
}

用法:

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; }
    }
}

【讨论】:

  • 很好的解决方案,只有Replace 只有在没有属性的情况下才有效
【解决方案2】:

您将需要创建占位符

在文件中会有几行:

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

占位符是 ${....}

然后你需要逐行解析文件。

您解析占位符。

在占位符中,字符串的第一部分是对象的名称。

因此,您需要将程序中的现有对象映射到文件中的对象。

然后,您使用该映射器创建容器

然后,您将文件中的对象映射到容器中的对象,并使用反射获得您在占位符中定义的值

另一种方式:

你只有占位符和映射器。

在文件中:

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

映射器(例如字典)

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

现在您需要获取占位符并替换为对象形式的字典。

反思并不重要

完整的工作示例(编译和测试)

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;
        }

    }

【讨论】:

  • 你能举个例子吗?
【解决方案3】:

根据 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);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-05-11
    • 2011-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-20
    相关资源
    最近更新 更多