Superpower: match a string with parser only if it begins a line

877 Views Asked by At

When parsing in superpower, how to match a string only if it is the first thing in a line?

For example, I need to match the A colon in "A: Hello Goodbye\n" but not in "Goodbye A: Hello\n"

3

There are 3 best solutions below

7
Craig.Feied On

Unless RegexOptions.Multiline is set, ^ matches the beginning of a string regardless of whether it is at the beginning of a line.

You can probably use inline (?m) to turn on multiline:

static TextParser<Unit> Actor { get; } =
  from start in Span.Regex(@"(?m)^[A-Za-z][A-Za-z0-9_]+:")
  select Unit.Value;
1
jtate On

Using your example here, I would change your ActorParser and NodeParser definitions to this:

public readonly static TokenListParser<Tokens, Node> ActorParser =
    from name in NameParser
    from colon in Token.EqualTo(Tokens.Colon)
    from text in TextParser
    select new Node {
        Actor = name + colon.ToStringValue(),
        Text = text
    };

public readonly static TokenListParser<Tokens, Node> NodeParser =
    from node in ActorParser.Try()
        .Or(TextParser.Select(text => new Node { Text = text }))
    select node;

I feel like there is a bug with Superpower, as I'm not sure why in the NodeParser I had to put a Try() on the first parser when chaining it with an Or(), but it would throw an error if I didn't add it.

Also, your validation when checking input[1] is incorrect (probably just a copy paste issue). It should be checking against "Goodbye A: Hello" and not "Hello A: Goodbye"

0
HuntK24 On

I have actually done something similar, but I do not use a Tokenizer.

private static string _keyPlaceholder;

private static TextParser<MyClass> Actor { get; } =
    Span.Regex("^[A-Za-z][A-Za-z0-9_]*:")
        .Then(x =>
             {
                 _keyPlaceholder = x.ToStringValue();
                 return Character.AnyChar.Many();
             }
         ))
    .Select(value => new MyClass { Key = _keyPlaceholder, Value = new string(value) });

I have not tested this, just wrote it out by memory. The above parser should have the following:

myClass.Key = "A:"
myClass.Value = " Hello Goodbye"