FParsec-如何解析由管道分隔的字符串?

时间:2018-07-24 13:51:53

标签: f# fparsec

为了娱乐,我正在使用FParsec编写一个小的组织模式解析器,并且在将表行解析为字符串列表时遇到了一些麻烦。我当前的代码如下:

let parseRowEntries :Parser<RowEntries, unit> =
    let skipInitialPipe = skipChar '|'
    let notaPipe  = function
        | '|' -> false
        | _ -> true
    let pipeSep = pchar '|'

    skipInitialPipe >>. sepEndBy (many1Satisfy notaPipe) pipeSep
    |>> RowEntries

这很好,直到您解析字符串|blah\n|blah\n|blah|为止,该字符串由于换行符而将失败。不幸的是,仅在\n条件下将notaPipe设置为false会导致解析器在第一个“ blah”之后停止并说它已被成功解析。我要的manySatisfy要做的是(几乎)解析任何字符,停在管道中,无法解析换行符(可能是eof字符)。

我尝试使用charsTillString,但这也只是在没有错误的情况下暂停了第一个管道的解析。

1 个答案:

答案 0 :(得分:1)

如果我正确理解了您的规格,则应该可以:

let parseOneRow :Parser<_, unit> =
    let notaPipe  = function
        | '|' -> false
        | '\n' -> false
        | _ -> true
    let pipe = pchar '|'

    pipe >>. manyTill (many1Satisfy notaPipe .>> pipe) (skipNewline <|> eof)

let parseRowEntries :Parser<_, unit> =
    many parseOneRow

run parseRowEntries "|row|with|four|columns|\n|second|row|"
// Success: [["row"; "with"; "four"; "columns"]; ["second"; "row"]]

结构是,每一行都以管道开头,然后一行中的段在概念上为row|with|,依此类推。 .>>组合器丢弃管道。该行的“填充”部分使用skipNewline而不是newline的原因是因为eof解析器返回unit,所以我们需要一个期望换行并返回{ {1}}。那就是unit解析器。

我尝试将换行符放在不属于它们的位置(例如,在管道之前),这导致该解析器完全失败。如果列为空(也就是skipNewline并排出现两个竖线字符),这也会失败,我认为这也是您想要的。如果要允许空行,只需使用||而不是manySatisfy