为了娱乐,我正在使用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
,但这也只是在没有错误的情况下暂停了第一个管道的解析。
答案 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
。