How to parse a string until the end with Superpower in C#

59 Views Asked by At

I'm trying to parse a string with Superpower in C#.

The following rules apply to the string to be valid:

  1. It has to start with a letter
  2. Only characters >= 0x20 and <= 0x7e are allowed
  3. In addition, the following characters are not allowed: '{', '}', '[', ']', ',', ';', ':', '(', ')'

I've created the following TextParser:

    public static TextParser<string> Name { get; } =
        from firstChar in Character.Letter
        from restOfString in Character.ExceptIn('{', '}', '[', ']', ',', ';', ':', '(', ')')
            .Where(c => c >= 0x20 && c <= 0x7e)
            .Many()
        select new string(firstChar + new string(restOfString));

When I try this with the input string "LC4711" it works, but "L{C4711" returns L but I want it to fail, because { is an invalid character.

How can I implement this correctly?

Thank you for any help / advise!

1

There are 1 best solutions below

2
jakub podhaisky On

The behavior you're observing occurs because your parser successfully finds a letter at the beginning and then attempts to parse the rest of the string based on your conditions. When it encounters an invalid character (like {), it stops parsing further but doesn't fail; it just returns what it has successfully parsed so far.

to fix this you can do following:

using Superpower;
using Superpower.Parsers;

public static class CustomParsers
{
    public static TextParser<string> Name { get; } =
        from firstChar in Character.Letter
        from restOfString in Character.ExceptIn('{', '}', '[', ']', ',', ';', ':', '(', ')')
            .Where(c => c >= 0x20 && c <= 0x7e)
            .Many()
        select new string(new[] { firstChar }.Concat(restOfString).ToArray());
}

Than in main or in any other class you are using your parser you can check whether it parsed or not by accesing the result

using Superpower;

public class Program
{
    public static void Main(string[] args)
    {
        var input = "L{C4711";
        var result = CustomParsers.Name.TryParse(input);

        if (!result.HasValue)
        {
            Console.WriteLine("Parsing failed.");
        }
        else if (!result.Remainder.IsAtEnd)
        {
            Console.WriteLine("Parsing did not consume the entire input.");
        }
        else
        {
            Console.WriteLine($"Parsed: {result.Value}");
        }
    }
}

please note that the input is currently hardcoded to get a quick way of checking if it works in a new project where only superpower is installed...

you will need to change this so it matches your codebase or you can encapsulate the ifchecks in a separate method