【问题标题】:Parse a text file into instances of a class based on keywords c#基于关键字 c# 将文本文件解析为类的实例
【发布时间】:2017-07-05 21:17:08
【问题描述】:

我有一个包含点列表的文本文件:

要点: 类型 5, 对象 ID 2, 设备类型猫, 标签“地址-1”, 描述“小猫”, 单位“磅”,

要点: 类型 5, 对象 ID 2, 设备类型猫, 标记“地址-2”, 描述“橙色小猫”, 单位“磅”,

要点: 类型 2, 对象 ID 3, 设备型狗, 标记“地址 5”, 描述“棕色狗”, 单位“磅”,

据此,我想创建我的类“Cat”的实例(在本例中为 2),其中包含此文本文件中的标记和描述(然后将它们放入 Cats 列表中)。我只想从类型 5 的点(那些是猫)中获取描述和标签。

我不确定获得我想要的字符串的最佳方法是什么。我需要在整个文件中搜索类型 5 的所有点,然后对于每个点,获取描述和标签并将其添加到新 Cat。

 public static void Main()
    {
        string line;
        List<Cat> catList = new List<Cat>();
        StreamReader file = new StreamReader(@"C:\Config\pets.txt");
        while((line = file.ReadLine()) != null)
        {
            string[] words = line.Split(',');
            catList.Add(new Cat cat1)
        }}

我最终这样做了:

 public static List<List<string>> Parse()
    {
        string filePath = @"C:\Config\pets.txt";
        string readText = File.ReadAllText(filePath);
        string[] stringSeparators = new string[] { "POINT:" }; //POINT is the keyword the text will be split on
        string[] result;


        result = readText.Split(stringSeparators, StringSplitOptions.None);
        List<List<string>> catData = new List<List<string>>();
        //split the text into an list of pieces
        List<string> tags = new List<string>(); //tags go here
        List<string> descriptions = new List<string>(); //descriptions go here
        foreach (string s in result)
        {
            if (s.Contains("TYPE 5")) //TYPE 5 = CAT
            {

                string[] parts = s.Split(','); //split the cat by commas
                string chop = "'"; //once tags and descriptions have been found, only want to keep what is inside single quotes ie 'orange kitty'
                foreach (string part in parts)
                {
                    if (part.Contains("TAG"))
                    {
                        int startIndex = part.IndexOf(chop);
                        int endIndex = part.LastIndexOf(chop);
                        int length = endIndex - startIndex + 1;
                        string path = part.Substring(startIndex, length);
                        tag = tag.Replace(chop, string.Empty);
                        tags.Add(tag);
                        //need to create instance of Cat with this tag
                    }
                    if (part.Contains("DESCRIPTION"))
                    {
                        int startIndex = part.IndexOf(chop);
                        int endIndex = part.LastIndexOf(chop);
                        int length = endIndex - startIndex + 1;
                        string description = part.Substring(startIndex, length);
                        description = description.Replace(chop, string.Empty);
                        descriptions.Add(description);
                        //need to add description to Cat instance that matches associated tag
                    }

                }
            }

        }

        catData.Add(tags);
        catData.Add(descriptions);
        return catData;

【问题讨论】:

  • 逐行读取文件,解析行并创建类的实例,然后将其添加到列表中。开始工作,然后问你写的代码有没有问题
  • 到目前为止你有什么?你有读取文件的代码吗?你有一个代表你想要填充的对象的类吗?给我们看相关代码!
  • 对于字符串解析,您可以使用正则表达式。如果你不方便,它看起来很简单,只需手动解析,查找关键字和逗号。
  • 添加了我最近的尝试。我想通过关键字'point'而不是字符来分割文件 - 问题是我没有看到任何可以分割的字符。有没有另一种方法可以将文件分成更小的块,然后我可以解析?
  • 这是一个开始。现在查看单词中的第一个条目,如果它与搜索到的文本匹配,则取第四个和第五个条目,删除不需要的部分(标签/描述),其余部分设置 Cat 类的属性

标签: c# file parsing text


【解决方案1】:

我要做的是创建一个代表您要捕获的字段的类。对于此示例,我将捕获所有字段,但您可以根据需要自定义它。我称这个类为“动物”,因为“点”似乎代表一种动物。

然后我将添加一个静态Parse 方法到类,该方法将根据一些输入字符串返回Animal 的实例。此方法将解析输入字符串并尝试根据字符串中的值设置Animal 对象的相关属性。

我还在类上添加了ToString() 覆盖,因此我们可以通过某种方式显示输出:

class Animal
{
    public int Type { get; set; }
    public int ObjectId { get; set; }
    public string DeviceType { get; set; }
    public string Tag { get; set; }
    public string Description { get; set; }
    public string Units { get; set; }

    /// <summary>
    /// Parses an input string and returns an Animal based
    /// on any property values found in the string
    /// </summary>
    /// <param name="input">The string to parse for property values</param>
    /// <returns>An animal instance with specified properties</returns>
    public static Animal Parse(string input)
    {
        var result = new Animal();
        if (string.IsNullOrWhiteSpace(input)) return result;

        // Parse input string and set fields accordingly
        var keyValueParts = input
            .Split(new [] {','}, StringSplitOptions.RemoveEmptyEntries)
            .Select(kvp => kvp.Trim());

        foreach (var keyValuePart in keyValueParts)
        {
            if (keyValuePart.StartsWith("Type", 
                StringComparison.OrdinalIgnoreCase))
            {
                int type;
                var value = keyValuePart.Substring("Type".Length).Trim();
                if (int.TryParse(value, out type))
                {
                    result.Type = type;
                }
            }
            else if (keyValuePart.StartsWith("Object Id", 
                StringComparison.OrdinalIgnoreCase))
            {
                int objectId;
                var value = keyValuePart.Substring("Object Id".Length).Trim();
                if (int.TryParse(value, out objectId))
                {
                    result.ObjectId = objectId;
                }
            }
            else if (keyValuePart.StartsWith("Device Type", 
                StringComparison.OrdinalIgnoreCase))
            {
                var value = keyValuePart.Substring("Device Type".Length).Trim();
                result.DeviceType = value;
            }
            else if (keyValuePart.StartsWith("Tag", 
                StringComparison.OrdinalIgnoreCase))
            {
                var value = keyValuePart.Substring("Tag".Length).Trim();
                result.Tag = value;
            }
            else if (keyValuePart.StartsWith("Description", 
                StringComparison.OrdinalIgnoreCase))
            {
                var value = keyValuePart.Substring("Description".Length).Trim();
                result.Description = value;
            }
            else if (keyValuePart.StartsWith("Units", 
                StringComparison.OrdinalIgnoreCase))
            {
                var value = keyValuePart.Substring("Units".Length).Trim();
                result.Units = value;
            }
        }

        return result;            
    }

    public override string ToString()
    {
        // Return a string that describes this animal
        var animalProperties = new StringBuilder();
        animalProperties.Append($"Type = {Type}, Object Id = {ObjectId}, ");
        animalProperties.Append($"Device Type = {DeviceType}, Tag = {Tag}, ");
        animalProperties.Append($"Description = {Description}, Units = {Units}");
        return animalProperties.ToString();
    }
}

现在我们有了一个可以从字符串创建自己的对象,我们只需要读入文件内容,用“Point:”关键字将其拆分,然后将每个字符串传递给Animal类即可获得我们的实例。

我添加了一些System.Linq 子句来过滤具有Type = 5 的动物(你说都是猫),因为你说那是你唯一感兴趣的动物。当然你可以删除它来获取所有动物,或将其替换为“狗”以获取狗等:

private static void Main()
{
    var filePath = @"f:\public\temp\temp.txt";

    // Read all file contents and split it on the word "Point:"
    var fileContents = Regex
        .Split(File.ReadAllText(filePath), "Point:", RegexOptions.IgnoreCase)
        .Where(point => !string.IsNullOrWhiteSpace(point))
        .Select(point => point.Trim());

    // Get all animals that are cats from the results
    var catList = fileContents
        .Select(Animal.Parse)
        .Where(animal => animal.Type == 5)
        .ToList();

    // Output results
    catList.ForEach(Console.WriteLine);

    // Wait for input before closing
    Console.WriteLine("\nDone!\nPress any key to exit...");
    Console.ReadKey();
}

输出

【讨论】:

  • 我最终进行了逐行解析,但您的策略肯定更优雅!谢谢您的帮助。如果您有兴趣,我将昨天提出的问题添加到我的问题中 - 但我想我可能会改变它!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-01-05
  • 2017-07-21
  • 2018-10-12
  • 2011-11-17
  • 1970-01-01
  • 1970-01-01
  • 2012-11-08
相关资源
最近更新 更多