Как я могу преобразовать список схемы текстового файла в рекурсивный набор объектов?

Как я могу преобразовать это содержание текстового файла в рекурсивный набор объектов, которые я могу связать с TreeView? т.е. Я хочу закончить с набором 3 объектов, первый, названный странами, который имеет набор трех дочерних объектов: Франция, Германия, Италия, и так далее...

ОТВЕТ: благодаря все, кто выручил на этом, вот являются моим кодом, который успешно анализирует эту текстовую схему в дерево XAML: http://tanguay.info/web/index.php?pg=codeExamples&id=358

countries
-france
--paris
--bordeaux
-germany
-italy
subjects
-math
--algebra
--calculus
-science
--chemistry
--biology
other
-this
-that

Код ниже - насколько я получил его, но он не имеет дело с несколькими детьми родителей правильно.

using System;
using System.Collections.Generic;
using System.Text;

namespace TestRecursive2342
{
    class Program
    {
        static void Main(string[] args)
        {
            List outlineObjects = new List();

            //convert file contents to object collection
            List lines = Helpers.GetFileAsLines();
            Stack stack = new Stack();
            foreach (var line in lines)
            {
                OutlineObject oo = new OutlineObject(line);

                if (stack.Count > 0)
                {
                    OutlineObject topObject = stack.Peek();
                    if (topObject.Indent < oo.Indent)
                    {
                        topObject.OutlineObjects.Add(oo);
                        stack.Push(oo);
                    }
                    else
                    {
                        stack.Pop();
                        stack.Push(oo);                        
                    }

                }
                else
                {
                    stack.Push(oo);
                }

                if(oo.Indent == 0)
                    outlineObjects.Add(oo);
            }

            outlineObjects.ForEach(oo => Console.WriteLine(oo.Line));

            Console.ReadLine();
        }
    }

    public class OutlineObject
    {
        public List OutlineObjects { get; set; }
        public string Line { get; set; }
        public int Indent { get; set; }

        public OutlineObject(string rawLine)
        {
            OutlineObjects = new List();
            Indent = rawLine.CountPrecedingDashes();
            Line = rawLine.Trim(new char[] { '-', ' ', '\t' });
        }
    }

    public static class Helpers
    {
        public static List GetFileAsLines()
        {
            return new List {
                "countries",
                "-france",
                "--paris",
                "--bordeaux",
                "-germany",
                "-italy",
                "subjects",
                "-math",
                "--algebra",
                "--calculus",
                "-science",
                "--chemistry",
                "--biology",
                "other",
                "-this",
                "-that"};
        }

        public static int CountPrecedingDashes(this string line)
        {
            int tabs = 0;
            StringBuilder sb = new StringBuilder();
            foreach (var c in line)
            {
                if (c == '-')
                    tabs++;
                else
                    break;
            }
            return tabs;
        }
    }
}

7
задан Edward Tanguay 25 February 2010 в 08:42
поделиться

5 ответов

public class Item
{
    public string Name;
    public Item Parent;
}

List<Item> Collection = new List<Item>();

public void Main()
{
    var DataSource = data.InnerText;

    StreamReader Reader = new StreamReader(MapPath("_test2.txt"));
    int LastLevel = 0;

    while (Reader.EndOfStream == false) {
        var line = Reader.ReadLine();
        var Level = line.Where((System.Object c) => c == "-").Count;
        Item LastItem = default(Item);

        if (Collection.Count != 0) {
            LastItem = Collection.Last();
        }

        if (Level == 0) {
            Collection.Add(new Item { Name = line });
            LastLevel = 0;
        }
        else if (Level - LastLevel == 1) {
            Collection.Add(new Item { Name = line, Parent = LastItem });
            LastLevel += 1;
        }
        else if (Level == LastLevel) {
            Collection.Add(new Item { Name = line, Parent = LastItem.Parent });
        }
        else if (Level < LastLevel) {
            var LevelDiff = LastLevel - Level;
            Item Parent = LastItem;

            for (i = 0; i <= LevelDiff; i++) {
                Parent = Parent.Parent;
            }

            LastLevel = Level;
            Collection.Add(new Item { Name = line, Parent = Parent });
        }
    }

    Reader.Close();
}

Это должно помочь. Я проверил это на вашем текстовом файле. Могут быть какие-то ошибки. Проверьте это и скажите, работает ли он.

РЕДАКТИРОВАТЬ: На самом деле после дальнейшего тестирования выяснилось, что это не работает должным образом. Вам нужно добавить больше логики, чтобы она работала. Я оставляю это на ваше усмотрение.

РЕДАКТИРОВАТЬ: Еще немного протестировав код, я пришел к версии, которая работает лучше. Я все еще не могу гарантировать, что он будет работать при любых обстоятельствах.

2
ответ дан 7 December 2019 в 16:41
поделиться

Вы должны сделать ваш OutlineObject списком дочерних OutlineObject s. Таким образом, вы можете привязаться к дочерней коллекции в древовидных представлениях.

См. Пример здесь . Или здесь .


Для синтаксического анализа вы должны поддерживать Stack ваших вложенных объектов. Когда вы читаете следующий OutlineObject , посмотрите на глубину последнего OutlineObject в стеке. Если ваш уровень выше, вы добавляете себя как потомок этого OutlineObject и помещаете свой OutlineObject в стек. Если ваш уровень такой же, вы удаляете этот OutlineObject и вместо этого нажимаете свой объект. Если ваш уровень больше, вы удалите верхний стек OutlineObject и повторите проверку.


Относительно изменения добавления

 if (topObject.Indent 

... этот код не проверяет случай, когда уровень нового объекта меньше уровня вершины стека. Вам понадобится:

...
else if (topObject.Indent == oo.Indent) 
{ 
  stack.Pop(); 
  stack.Push(oo); 
} 
else 
{ 
  while (stack.Top().Indent >= oo.Indent) 
    stack.Pop(); 
  stack.Push(oo); 
}
1
ответ дан 7 December 2019 в 16:41
поделиться

Просто.

Создайте список объектов OutlineObject, по одному для каждого уровня, они будут служить родительскими объектами.

Итак, алгоритм:

  1. Создайте объект из строки
  2. Найдите уровень отступа (который будет равен 0 для корневых объектов)
  3. Если в списке родителей меньше уровня + 1 количество элементов, добавляйте «нулевые» элементы до тех пор, пока их не будет достаточно (что означает, что для первого корневого объекта добавьте «нулевой» элемент, чтобы он имел 1 элемент)
  4. Замените элемент #level в этом списке новым созданным вами объектом в 1. (поскольку список основан на 0, корневые объекты будут первыми)
  5. Если уровень> 0, добавить его как дочерний элемент к родителям [уровень-1], если уровень == 0, добавить это как корневой объект

Это должно дать вам древовидную структуру. Вам нужно будет вести дочерний список в каждом объекте.

Также обратите внимание, что в приведенном выше списке потребуется дополнительная проверка ошибок, если вы хотите, чтобы он обрабатывал ошибки в файле, например:

root
-child 1
--child 2
another root
--child 3 (note that we skipped a level)

В этом случае последний дочерний элемент будет добавлен как дочерний элемент «child 1» , а не "другого корня".

0
ответ дан 7 December 2019 в 16:41
поделиться

Шаблон Composite - это первое, что приходит мне на ум...

0
ответ дан 7 December 2019 в 16:41
поделиться

Вот моя попытка, которая представляет собой комбинацию ваших оригинальных усилий и подхода Диамандиева. Я также добавил рекурсивный метод Output (), который эффективно воспроизводит исходный входной файл.

К сожалению, я не мог полностью понять стековый подход, но мне было бы интересно увидеть рабочий пример.

Обратите внимание, что это позволяет только для данного примера узлов, вложенных на 3 уровня в глубину. Любое большее, чем это, потребует модификации проверки else if ((oo.Indent - lastItem.Indent) <0) .

using System;
using System.Collections.Generic;
using System.Text;

namespace TestRecursive2342
{
    class Program
    {
        static void Main(string[] args)
        {
            List<OutlineObject> outlineObjects = new List<OutlineObject>();

            //convert file contents to object collection 
            List<string> lines = Helpers.GetFileAsLines();

            OutlineObject lastItem = new OutlineObject();
            bool processOk = true;

            foreach (var line in lines)
            {
                OutlineObject oo = new OutlineObject(line);

                if (lastItem.Indent != -1)
                {
                    if (oo.Indent == 0 && lastItem.Indent != 0)
                    {
                        // we've got a new root node item, so add the last item's top level parent to the list
                        while (lastItem.parent != null)
                            lastItem = lastItem.parent;

                        outlineObjects.Add(lastItem);
                    }
                    else if ((oo.Indent - lastItem.Indent) == 1)
                    {
                        // new item is one level lower than the last item
                        oo.parent = lastItem;
                        lastItem.OutlineObjects.Add(oo);
                    }
                    else if (oo.Indent == lastItem.Indent)
                    {
                        // new item is at the same level as the last item
                        oo.parent = lastItem.parent;
                        lastItem.parent.OutlineObjects.Add(oo);
                    }
                    else if ((oo.Indent - lastItem.Indent) < 0)
                    {
                        // new item is above the last item, but not a root node
                        // NB: this only allows for an item to be two levels above the last item
                        oo.parent = lastItem.parent.parent;
                        lastItem.parent.parent.OutlineObjects.Add(oo);
                    }
                    else if ((oo.Indent - lastItem.Indent) > 1)
                    {
                        // missing node check
                        Console.WriteLine("ERROR: missing node in input file between \"{0}\" and \"{1}\"", lastItem.Line, oo.Line);
                        processOk = false;
                        break;
                    }
                }

                lastItem = oo;
            }

            if (processOk)
            {
                // flush the last item
                while (lastItem.parent != null)
                    lastItem = lastItem.parent;

                outlineObjects.Add(lastItem);

                outlineObjects.ForEach(oo => oo.Output());
            }

            Console.ReadLine();
        }
    }

    public class OutlineObject
    {
        public OutlineObject parent { get; set; }
        public List<OutlineObject> OutlineObjects { get; set; }

        public string Line { get; set; }
        public int Indent { get; set; }

        public void Output()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append('-', this.Indent);
            sb.Append(this.Line);

            Console.WriteLine(sb);

            foreach (OutlineObject oChild in this.OutlineObjects)
            {
                oChild.Output();
            }
        }

        public OutlineObject()
        {
            parent = null;
            OutlineObjects = new List<OutlineObject>();
            Line = "";
            Indent = -1;
        }

        public OutlineObject(string rawLine)
        {
            OutlineObjects = new List<OutlineObject>();
            Indent = rawLine.CountPrecedingDashes();
            Line = rawLine.Trim(new char[] { '-', ' ', '\t' });
        }
    }

    public static class Helpers
    {
        public static List<string> GetFileAsLines()
        {
            return new List<string> { 
                "countries", 
                "-france", 
                "--paris", 
                "--bordeaux", 
                "-germany", 
                "-italy", 
                "subjects", 
                "-math", 
                "--algebra", 
                "--calculus", 
                "-science", 
                "--chemistry", 
                "--biology", 
                "other", 
                "-this", 
                "-that"};
        }

        public static int CountPrecedingDashes(this string line)
        {
            int tabs = 0;

            foreach (var c in line)
            {
                if (c == '-')
                    tabs++;
                else
                    break;
            }
            return tabs;
        }
    }
}
0
ответ дан 7 December 2019 в 16:41
поделиться
Другие вопросы по тегам:

Похожие вопросы: