superpower

Superpower: Create parser to Match against "\r\n" or "\n" ( More general: match against a string literal)


I want to create a parser for EOL, I can't just do whitespace because I need it to ignore spaces.

So I want to create a parser that will match on "\r\n" or '\n'. Doing a single character is easy Character.EqualTo('\n') but trying to match a specific string literal is perplexing me. I would think this should be a regular thing that needs to be done for keywords, but I am at a loss.


Solution

  • The \r\n combination is a string, which means that you need to combine the simple \n parser (that is a character parser) with a string parser.

    How about:

        public static void Main()
        {
                var crlf = 
                    from carriageReturn in Character.EqualTo('\r')
                    from lineFeed in Character.EqualTo('\n')
                    select new string(carriageReturn, 1) + lineFeed;
    
                var lf =
                    from lineFeed in Character.EqualTo('\n')
                    select new string(lineFeed, 1);
    
                var eol = crlf.Or(lf);
            
            
            eol.TryParse("\r\n").Dump();  // Successful parsing of \r\n
            eol.TryParse("\n").Dump();    // Successful parsing of \n
            eol.TryParse("\r").Dump();    // Syntax error: unexpected end of input, expected line feed.
        }
    

    If you prefer the non-LINQ syntax:

                var eol = Character.EqualTo('\r')
                    .Then(carriageReturn => Character.EqualTo('\n').Select( lineFeed => new [] {carriageReturn, lineFeed}))
                    .Or(Character.EqualTo('\n').Select(lineFeed => new[] { lineFeed }));
    
    

    Edited: Use the Span parser to parse strings:

                var eol = Span.EqualTo("\n")
                    .Or(Span.EqualTo("\r\n"));