Sprache解析器和字符转义

时间:2015-09-28 20:38:43

标签: c# .net parsing sprache

我还没有找到一个例子 - 如何处理字符转义。我找到了一个代码示例:

static void Main(string[] args)
{
    string text = "'test \\\' text'";
    var result = Grammar.QuotedText.End().Parse(text);
}

public static class Grammar
{
    private static readonly Parser<char> QuoteEscape = Parse.Char('\\');
    private static Parser<T> Escaped<T>(Parser<T> following)
    {
        return from escape in QuoteEscape
               from f in following
               select f;
    }

    private static readonly Parser<char> QuotedTextDelimiter = Parse.Char('\'');

      private static readonly Parser<char> QuotedContent =
          Parse.AnyChar.Except(QuotedTextDelimiter).Or(Escaped(QuotedTextDelimiter));

    public static Parser<string> QuotedText = (
        from lquot in QuotedTextDelimiter
        from content in QuotedContent.Many().Text()
        from rquot in QuotedTextDelimiter
        select content
        ).Token();
}

如果文本不包含转义,它会成功解析文本,但它不会解析带有字符转义的文本。

1 个答案:

答案 0 :(得分:3)

我遇到了类似的问题,使用"作为分隔符解析字符串,使用\作为转义字符解析字符串。我为此编写了一个简单的解析器(可能不是最优雅的解决方案),它看起来效果很好。

你应该能够适应它,因为唯一的区别似乎是分隔符。

var escapedDelimiter = Parse.String("\\\"").Text().Named("Escaped delimiter");
var singleEscape = Parse.String("\\").Text().Named("Single escape character");
var doubleEscape = Parse.String("\\\\").Text().Named("Escaped escape character");
var delimiter = Parse.Char('"').Named("Delimiter");
var simpleLiteral = Parse.AnyChar.Except(singleEscape).Except(delimiter).Many().Text().Named("Literal without escape/delimiter character");

var stringLiteral = (from start in delimiter
            from v in escapedDelimiter.Or(doubleEscape).Or(singleEscape).Or(simpleLiteral).Many()
            from end in delimiter
            select string.Concat(start) + string.Concat(v) + string.Concat(end));

关键部分是from v in ...。它首先搜索转义分隔符,然后搜索双转义字符,然后搜索单个转义字符,然后尝试将其解析为&#34; simpleLiteral&#34;没有任何转义或分隔符字符。更改此处的顺序将导致解析错误(例如,如果您尝试在转义分隔符之前解析单个转义符,则永远不会找到后者,对于双转义和单个转义同样如此)。 此步骤重复多次,直到出现未转义的分隔符(from v in ...不处理未转义的分隔符,但from end in delimiter当然会这样做。