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

StackOverflow https://stackoverflow.com/questions/13963

  •  08-06-2019
  •  | 
  •  

Вопрос

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

[KEY:Value]     
    [SUBKEY:SubValue]

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

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

Это было полезно?

Решение

Я рассматривал это, но я не собираюсь использовать 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 довольно прост, так что "насколько это может быть сложно?" :-)

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

Другие советы

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

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

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

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

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

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

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

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

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

Вы также можете использовать стек и использовать алгоритм 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";
    }

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

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

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

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

@Gishu

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

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

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top