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

F# FParsec-如何解析由管道分隔的字符串?,f#,fparsec,F#,Fparsec,为了好玩,我使用FParsec编写了一个小型的组织模式解析器,在将表行解析为字符串列表时遇到了一些麻烦。我当前的代码如下所示: let parseRowEntries :Parser<RowEntries, unit> = let skipInitialPipe = skipChar '|' let notaPipe = function | '|' -> false | _ -> true let pipeSep

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

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

    skipInitialPipe >>. sepEndBy (many1Satisfy notaPipe) pipeSep
    |>> RowEntries
let parseRowEntries:解析器=
设skipInitialPipe=skipChar'|'
让我们看看管道=函数
|“|”->错误
|_uu->true
设pipeSep=pchar'|'
SkipInInitialPipe>>。分离(多管道)管道SEP
|>>划船项目
在解析字符串
| blah\n | blah\n | blah |
之前,这一切都很正常,但由于换行符的原因,该字符串应该会失败。不幸的是,在
notaPipe
条件中简单地将
\n
设为false会导致解析器在第一个“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"]]
let parseOneRow:Parser=
让我们看看管道=函数
|“|”->错误
|'\n'->错误
|_uu->true
让管道=pchar'|'
管道>>。manyTill(Many1管道>>管道)(skipNewline eof)
让parseRowEntries:解析器=
许多帕塞诺人
运行parseRowEntries“|行|和|四列| \n |第二行|”
//成功:[“行”;“带”;“四”;“列”];[“第二行”;“行”]]
其结构是,每行以一个管道开始,然后一行中的段在概念上是
行|
带|
,依此类推。
组合器丢弃管道。该行的“till”部分使用
skipNewline
而不是
newline
的原因是
eof
解析器返回
unit
,因此我们需要一个需要换行并返回
unit
的解析器。这就是
skipNewline
解析器


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

,因此规则是一行必须以管道字符开头和结尾,对吗?也就是说,
|foo | \n | bar | \n
有效,但是
|foo\n | bar\n
无效,因为没有终止管道?在这种情况下,我认为您需要的是使用
介于
之间的组合器。我会做一些测试,然后用我的发现写一个答案。我尝试了
between
组合符,但是分隔符与结束字符相同的事实使得
between
解析器的使用有点棘手。这可能是可行的,但我最终选择了另一种方法,而不是找出如何使
之间工作。我也尝试使用between解析器,但还是绕圈了。开头和结尾的
|
将我抛出了一个循环。我做的一个小改动是将many1Satisfy变成manySatisfy(因为从技术上讲
|
是一个有效的条目)。