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

FParsec - how to parse strings separated by pipes?

为了好玩,我正在使用 FParsec 编写一个小型组织模式解析器,但在将 table 行解析为字符串列表时遇到了一些麻烦。我当前的代码如下所示:

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| 之前它工作正常,该字符串应该因换行符而失败。不幸的是,简单地在 notaPipe 条件下使 \n 为假会导致解析器在第一个 'blah' 之后停止并说它已成功解析。我想要 manySatisfy 做的是解析(几乎)任何字符,在管道处停止,无法解析换行符(可能是 eof 字符)。

我试过使用 charsTillString 但这也只是在第一个管道停止解析,没有错误。

如果我没有正确理解你的规格,这应该有效:

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|,依此类推。 .>> 组合器丢弃管道。该行的 "till" 部分使用 skipNewline 而不是 newline 的原因是因为 eof 解析器 returns unit,所以我们需要一个解析器需要换行符和 returns unit。那是 skipNewline 解析器。

我试过在不属于它们的地方(例如,在管道之前)抛出换行符,这会导致这个解析器完全按照它应该的方式失败。如果列为空(即两个管道字符并排出现,如 ||),它也会失败,我认为这也是您想要的。如果要允许空行,只需使用 manySatisfy 而不是 many1Satisfy.