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
.
为了好玩,我正在使用 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
.