问题
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"
回答1:
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"
回答2:
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;
回答3:
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"
来源:https://stackoverflow.com/questions/52706549/superpower-match-a-string-with-parser-only-if-it-begins-a-line