I'm working on building a parser with the SuperPower library.
Here's a sample of the source input that I want to parse:
|ABC|xyz|1 3|~~~|
|
is the OpeningPipe
.|
is the ClosingPipe
.|
are delimiters.new string[]{"ABC", "xyz", "1 3", "~~~"}
I think that the trouble I'm having is that my delimiter character is the same as my ClosingPipe
character.
How should I build this TextParser<string[]>
?
Here are some parsers that should work for you:
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();
Then use it like so:
string[] result = Parser.Parse("|ABC|xyz|1 3|~~~|");
And result
should be { "ABC", "xyz", "1 3", "~~~" }
The idea is to parse out the opening pipe, first content, then the closing pipe, and then since (I'm assuming) the rest of the number of delimiters can change, you can use Superpower's built in method ManyDelimitedBy
to parse out as many other content pieces as there are, separated by pipes. But since your input always has a pipe at the end, the ManyDelimitedBy
will leave an empty string at the end of the contents
array, which I'm removing before returning the final output.
Here is a way to do it without having to chop off the empty string:
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();