Лучший метод разбора текстового файла в C #?

Я хочу разобрать что-то вроде конфигурационного файла, вот так:

[KEY:Value]     
    [SUBKEY:SubValue]

Теперь я начал с StreamReaderпреобразования строк в массивы символов, когда решил, что должен быть лучший способ. Поэтому я прошу вас, скромный читатель, помочь мне.

Одним из ограничений является то, что он должен работать в среде Linux / Mono (если быть точным, 1.2.6). У меня нет последней версии 2.0 (из Mono), поэтому попробуйте ограничить языковые возможности до C # 2.0 или C # 1.0.

17.08.2008 22:02:31
8 ОТВЕТОВ
РЕШЕНИЕ

Я рассмотрел это, но я не собираюсь использовать XML. Я собираюсь писать это вручную, а редактирование XML вручную делает мой мозг болящим. : ')

Вы смотрели на YAML ?

Вы получаете преимущества XML без всякой боли и страданий. Он широко используется в сообществе ruby ​​для таких вещей, как файлы конфигурации, предварительно подготовленные данные базы данных и т. Д.

вот пример

customer:
  name: Orion
  age: 26
  addresses:
    - type: Work
      number: 12
      street: Bob Street
    - type: Home
      number: 15
      street: Secret Road

Здесь, похоже, есть библиотека C # , которую я лично не использовал, но yaml довольно прост, так что "как это может быть сложно?" :-)

Я бы сказал, что предпочтительнее изобретать свой собственный специальный формат (и иметь дело с ошибками парсера)

12
17.08.2008 22:46:20

Мне кажется, что вам лучше использовать конфигурационный файл на основе XML, поскольку уже есть классы .NET, которые могут относительно легко считывать и хранить информацию для вас. Есть ли причина, по которой это невозможно?

@Bernard: Это правда, что ручное редактирование XML утомительно, но структура, которую вы представляете, уже очень похожа на XML.

Тогда да, есть хороший метод там.

0
17.08.2008 22:39:34

Вы также можете использовать стек и использовать алгоритм push / pop. Этот соответствует открывающим / закрывающим тегам.

public string check()
    {
        ArrayList tags = getTags();


        int stackSize = tags.Count;

        Stack stack = new Stack(stackSize);

        foreach (string tag in tags)
        {
            if (!tag.Contains('/'))
            {
                stack.push(tag);
            }
            else
            {
                if (!stack.isEmpty())
                {
                    string startTag = stack.pop();
                    startTag = startTag.Substring(1, startTag.Length - 1);
                    string endTag = tag.Substring(2, tag.Length - 2);
                    if (!startTag.Equals(endTag))
                    {
                        return "Fout: geen matchende eindtag";
                    }
                }
                else
                {
                    return "Fout: geen matchende openeningstag";
                }
            }
        }

        if (!stack.isEmpty())
        {
            return "Fout: geen matchende eindtag";
        }            
        return "Xml is valid";
    }

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

0
17.08.2008 22:12:19

Я смотрел почти на эту проблему на днях: эта статья о токенизации строк именно то, что вам нужно. Вы захотите определить свои токены как что-то вроде:

@"(?&ltlevel>\s) | " +
@"(?&ltterm>[^:\s]) | " +
@"(?&ltseparator>:)"

Статья довольно хорошо объясняет это. Оттуда вы просто начинаете есть токены, как считаете нужным.

Подсказка: для парсера LL (1) (читай: легко) токены не могут иметь общий префикс. Если у вас есть abcв качестве токена, вы не можете иметь aceв качестве токена

Примечание: в статье отсутствует | символы в его примерах, просто добавьте их.

4
17.08.2008 22:25:55

Использование библиотеки почти всегда предпочтительнее, чем использование собственных. Вот краткий список пунктов «О, я никогда не буду нуждаться в этом / я не думал об этом», которые в конечном итоге придут к вам позже:

  • Спасаясь от персонажей. Что, если вы хотите: в ключе или] в значении?
  • Спасаясь от побега персонажа.
  • Unicode
  • Сочетание табуляции и пробелов (см. Проблемы с синтаксисом, чувствительным к пробелам в Python)
  • Обработка различных форматов возвращаемых символов
  • Обработка сообщений о синтаксических ошибках

Как и предполагали другие, YAML выглядит как ваша лучшая ставка.

1
29.12.2015 02:45:57

Независимо от сохраняемого формата использование Regex будет самым быстрым способом анализа. В ruby, вероятно, будет несколько строк кода.

\[KEY:(.*)\] 
\[SUBKEY:(.*)\]

Эти два получили бы значение и SubValue в первой группе. Проверьте MSDN о том, как сопоставить регулярное выражение со строкой.

Это то, что каждый должен иметь в своем котенке. Дни до Регекса выглядели как Ледниковый период.

-1
18.08.2008 07:22:11

@Gishu

На самом деле, когда я учел экранированные символы, мое регулярное выражение работало немного медленнее, чем мой рекурсивный синтаксический анализатор, написанный сверху вниз, и это без вложенности (связывающей подэлементы с их родителями) и сообщений об ошибках, которые имел рукописный синтаксический анализатор.

Регулярное выражение было немного быстрее для написания (хотя у меня есть некоторый опыт работы с парсерами), но это без хорошего сообщения об ошибках. Как только вы добавите, это становится немного сложнее и дольше делать.

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

private static Node ParseNode(TextReader reader)
{
    Node node = new Node();
    int indentation = ParseWhitespace(reader);
    Expect(reader, '[');
    node.Key = ParseTerminatedString(reader, ':');
    node.Value = ParseTerminatedString(reader, ']');
}
0
18.08.2008 07:52:29

Существует еще одна библиотека YAML для .NET, которая находится в стадии разработки. Прямо сейчас он поддерживает чтение потоков YAML и был протестирован на Windows и Mono. Поддержка записи в настоящее время осуществляется.

1
26.08.2008 23:33:36