5

作为后续:如何使用 fparsec 测试恰好 2 个字符?

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

例如:

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.

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

这可以做到吗?如果可以,怎么做?

4

2 回答 2

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
于 2013-05-14T10:04:29.707 回答
3

我想notFollowedBy这就是你要找的。这应该可以解决问题:

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

let freeform = manyChars (notFollowedBy identifier >>. anyChar)
于 2013-05-14T09:28:46.763 回答