分析器标识符和自由格式文本。这可以用FParsec完成吗?

时间:2013-05-14 03:33:33

标签: f# fparsec

作为后续行动:How do I test for exactly 2 characters with fparsec?

我需要解析一个字符串,该字符串由一对标识符组成,后跟自由格式文本。我可以很容易地构造一个解析器,它找到了newline形式的标识符,后面跟着一个空格,后面跟着一个空格。与前面的标识符相关联的自由格式文本是标识符之后的所有内容,但不包括下一个标识符。

例如:

AB Now is the
time for all good
men.
CD Four score and seven years ago EF our.

包含两个标识符ABCD以及两个自由格式文本

Now is the \ntime for all good men.
Four score and seven years ago EF our.

我的问题是我不知道如何构造一个与自由格式文本匹配但与标识符不匹配的解析器。这是我需要做回溯的情况吗?

可以这样做,如果是这样的话?

2 个答案:

答案 0 :(得分:4)

Tarmil发布了直截了当的解决方案。

这是另一个变体,它在开头不需要换行符,只在行尾检查以下标识符:

let id = manyMinMaxSatisfyL 2 2 isUpper "ID" .>> pchar ' '

let text = 
    stringsSepBy (restOfLine true) 
                 ((notFollowedBy ((id >>% ()) <|> skipNewline <|> eof)) >>% "\n")

let parser = many (id .>>. text)

如果您想优化与stringsSepBy组合子一起使用的第二个解析器,可以使用以下版本替换它:

let notFollowedByIdOrEmptyLineOrEof : Parser<string,_> =
    fun stream ->
        let cs = stream.Peek2()
        let c0, c1 = cs.Char0, cs.Char1
        if c0 = '\r' || c0 = '\n' || c0 = EOS
           || (isUpper c0 && isUpper c1 && stream.Peek(2) = ' ')
        then Reply(Error, NoErrorMessages)
        else Reply("\n")

let text2 = stringsSepBy (restOfLine true) 
                         notFollowedByIdOrEmptyLineOrEof

答案 1 :(得分:3)

我认为notFollowedBy正是您所寻找的。这应该可以解决问题:

// adapted from the other question
let identifier = skipNewline >>. manyMinMaxSatisfy 2 2 CharParsers.isUpper

let freeform = manyChars (notFollowedBy identifier >>. anyChar)