Парсинг столбцов текстового файла

Каким способом можно спарсить столбцы и добавить их в класс. А затем к ним обратиться по мере надобности

public class Detail
{
    public string Ch { get; set; }
    public string Type { get; set; }
    public string Duplex { get; set; }
    public string Speed { get; set; }
    public string Neg { get; set; }
    ...   
}

Пример данных, которые нужно спарсить:

Ch       Type    Duplex  Speed  Neg      control  State         Port Mode (VLAN)        
-------- ------- ------  -----  -------- -------  ------------- ------------------------
Po1         --     --      --      --       --    Not Present   Access (1)              
Po2         --     --      --      --       --    Not Present   Access (1)              
Po3         --     --      --      --       --    Not Present   Access (1)              
Po4         --     --      --      --       --    Not Present   Access (1)                

      

Дополнение

Видел в интернет что то подобное, но это не работает. Не знаю как обратиться к неинициализированному объекту

Parse(log, ' ');

public IEnumerable<Detail> Parse(string source, char delimiter)
{
    return source.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries).Skip(1)
        .Select(x =>
        {
            var detail = x.Split(new[] { delimiter });
            return new Detail
            {
                Ch = detail[0],
                Type = detail[1],
                Duplex = detail[2],
                Speed = detail[3],
                Neg = detail[4]
            };
        });
}

Ответы (2 шт):

Автор решения: motpfofs

Я немного поправил код, который вы предложили. Это однозначно не самое оптимальное решение и я уверен, что предложат лучше, но всё же:

  1. С помощью регулярных выражений заменяем все пробелы (которые идут подряд больше двух) на определённый нами сепаратор
  2. Разбиваем строку используя наш сепаратор
public static IEnumerable<Detail> ParseLog(string source)
{
    return source.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries).Skip(2)
        .Select(x =>
        {
            RegexOptions options = RegexOptions.None;
            Regex regex = new Regex("[ ]{2,}", options);
            x = regex.Replace(x, "#sep#");

            var detail = x.Split("#sep#");
            return new Detail
            {
                Ch = detail[0].Trim(),
                Type = detail[1].Trim(),
                Duplex = detail[2].Trim(),
                Speed = detail[3].Trim(),
                Neg = detail[4].Trim()
            };
        });
}
→ Ссылка
Автор решения: aepot

Немного монструозно получилось, но решал без регулярок и в лоб. На гениальность не претендую.

class Program
{
    static void Main(string[] args)
    {
        string text = @"Ch       Type    Duplex  Speed  Neg      control  State         Port Mode (VLAN)        
-------- ------- ------  -----  -------- -------  ------------- ------------------------
Po1         --     --      --      --       --    Not Present   Access (1)              
Po2         --     --      --      --       --    Not Present   Access (1)              
Po3         --     --      --      --       --    Not Present   Access (1)              
Po4         --     --      --      --       --    Not Present   Access (1)    ";

        foreach (Detail d in ParseLog(text))
            Console.WriteLine(d);

        Console.ReadKey();
    }

    public static IEnumerable<Detail> ParseLog(string source)
    {
        string[] lines = source.Replace(Environment.NewLine, "\n").Split('\n');

        List<(int, int)> columnsIndex = new List<(int, int)>();
        int start = 0;
        bool isHeader = false;
        for (int i = 0; i < lines[1].Length; i++)
        {
            if (!isHeader && lines[1][i] == '-')
            {
                start = i;
                isHeader = true;
            }
            else if (isHeader && (lines[1][i] == ' ' || i == lines[1].Length - 1))
            {
                columnsIndex.Add((start, i - start));
                isHeader = false;
            }
        }

        foreach (string line in lines.Skip(2))
        {
            List<string> values = new List<string>();
            foreach ((int offset, int length) in columnsIndex)
            {
                values.Add(line.Substring(offset, offset + length > line.Length ? line.Length - offset : length).Trim());
            }
            if (values.Count > 7)
                yield return new Detail
                {
                    Ch = values[0],
                    Type = values[1],
                    Duplex = values[2],
                    Speed = values[3],
                    Neg = values[4],
                    Control = values[5],
                    State = values[6],
                    PortMode = values[7],
                };
        }
    }
}

public class Detail
{
    public string Ch { get; set; }
    public string Type { get; set; }
    public string Duplex { get; set; }
    public string Speed { get; set; }
    public string Neg { get; set; }
    public string Control { get; set; }
    public string State { get; set; }
    public string PortMode { get; set; }

    public override string ToString()
        => string.Join(", ", GetType().GetProperties().Select(x => x.GetValue(this)));
}

Вывод в консоль

Po1, --, --, --, --, --, Not Present, Access (1)
Po2, --, --, --, --, --, Not Present, Access (1)
Po3, --, --, --, --, --, Not Present, Access (1)
Po4, --, --, --, --, --, Not Present, Access (1)
→ Ссылка