Сведения о вопросе

Oleksandr

00:23, 14th August, 2020

Теги

c#   fileparse    

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

Просмотров: 467   Ответов: 8

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

[KEY:Value]     
    [SUBKEY:SubValue]

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

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



  Сведения об ответе

screen

05:48, 14th August, 2020

Я подумал об этом, но не собираюсь использовать 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 довольно прост, так что "how hard can it be?" :-)

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


  Сведения об ответе

dump

17:16, 13th August, 2020

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

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

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

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

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


  Сведения об ответе

LAST

01:48, 17th August, 2020

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

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

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


  Сведения об ответе

DAAA

02:38, 13th August, 2020

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


  Сведения об ответе

COOL

08:32, 13th August, 2020

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

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

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


  Сведения об ответе

screen

05:56, 16th August, 2020

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

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


  Сведения об ответе

lool

15:46, 20th August, 2020

@Gishu

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

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

Я также считаю, что рукописный парсер легче понять намерение. Например, вот фрагмент кода 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, ']');
}


  Сведения об ответе

piter

21:49, 18th August, 2020

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

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

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

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


Ответить на вопрос

Чтобы ответить на вопрос вам нужно войти в систему или зарегистрироваться