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