Попытка построить TextParser<string []> с одинаковыми символами открытия / закрытия / разделителя

Я работаю над созданием парсера с библиотекой SuperPower.

Вот пример исходного ввода, который я хочу проанализировать:

|ABC|xyz|1 3|~~~|

  • Первый | это OpeningPipe,
  • Последний | это ClosingPipe,
  • 2-й, 3-й и 4-й | являются разделителями.
  • В конечном счете, я хотел бы иметь возможность создавать эту структуру во время синтаксического анализа:
new string[]{"ABC", "xyz", "1 3", "~~~"}

Я думаю, что проблема у меня в том, что мой символ разделителя такой же, как мой ClosingPipe характер.

Как я должен построить это TextParser<string[]>?

1 ответ

Решение

Вот некоторые парсеры, которые должны работать на вас:

public static TextParser<char> Pipe =>
    from c in Character.EqualTo('|')
    select c;

public static TextParser<string> Content =>
    from c in Character.Except('|').Many()
    select new string(c);

public static TextParser<string[]> Parser =>
    from openingPipe in Pipe
    from content1 in Content
    from closingPipe in Pipe
    from contents in Content.ManyDelimitedBy(Pipe)
    select new[] { content1 }
        .Concat(contents.Take(contents.Length - 1)) // remove the empty string on the end
        .ToArray();

Тогда используйте это так:

string[] result = Parser.Parse("|ABC|xyz|1 3|~~~|");

А также result должно быть { "ABC", "xyz", "1 3", "~~~" }

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

РЕДАКТИРОВАТЬ

Вот способ сделать это без необходимости отрубать пустую строку:

public static TextParser<string> ExtraContent =>
    from content in Content
    from pipe in Pipe
    select content;

public static TextParser<string[]> Parser2 =>
    from openingPipe in Pipe
    from content1 in Content
    from closingPipe in Pipe
    from contents in ExtraContent.Many()
    select new[] { content1 }.Concat(contents).ToArray();
Другие вопросы по тегам