haskell - Haskell Parsec - 解析两个东西列表
问题描述
我使用Advent of Code 第 16 部分作为学习如何使用 Parsec 的借口,但我在如何处理这种特定情况下磕磕绊绊。
输入采用以下格式:
Before: [3, 2, 3, 0]
2 3 1 1
After: [3, 2, 3, 0]
Before: [1, 0, 2, 1]
7 0 1 1
After: [1, 1, 2, 1]
...
Before: [0, 0, 2, 1]
6 2 3 1
After: [0, 6, 2, 1]
5 0 2 3
5 1 3 1
...
5 3 2 2
换句话说,首先是一组三行,它们被解析成一个结构,用空行分隔,然后是三个空行,然后是四位数字的行数。
我为每个结构都有工作解析器 -Sample
并且MaskedOperation
,解析器sample
和maskedOp
分别为1 - 但我不知道如何将它们放在一起以将其解析为([Sample], [MaskedOperation])
.
我尝试了以下方法:
parseInput :: GenParser Char st ([Sample], [MaskedOperation])
parseInput = do
samples <- sample `sepBy` (count 2 newline) <* count 3 newline
operations <- maskedOp `sepBy` newline
return (samples, operations)
但是当它到达三个换行符时它会失败,期待另一个样本:
(line 3221, column 1):
unexpected "\n"
expecting "Before:"
我如何告诉 parsec 我想尽可能多地使用,然后使用分隔符(额外的换行符),然后开始阅读其他内容?
1阅读 Advent of Code 问题的上下文;名字并不重要。
解决方案
恐怕你不能sepBy
在这里使用。
让我们将其简化为将“a”解析为样本,将“b”解析为换行符。您将解析字符串,例如
a b b a b b b c b c b c b
那么解析器在遍历这样的字符串时会怎么想呢?让我们来看看:
解析
a
或空序列
[a] b b a b b b c b c b c b
哦,一个
a
。该序列是非空的,所以我many
"bb" >> "a"
将从现在开始解析。
a [b b a] b b b c b c b c b
成功!让我们再吃点或完成
a b b a [b b] b c b c b c b
好的,我找到了另一个
bb
,所以顺序继续。解析a
a b b a b b [b] c b c b c b
笏
问题是解析器不会回滚,除非明确要求这样做。要赋予解析器回滚能力,您必须使用try
组合器对其进行标记,否则它将无法“取消消费”消耗的输入。
目前,我没有看到比重写sepBy
组合器更好的方法,以使其意识到在解析每个分隔符后,如果解析separator >> target
失败,可能需要将其返回到缓冲区:
sepTry a sep = sepTry1 a sep <|> pure []
sepTry1 a sep = liftA2 (:) a (many (try $ sep *> a))
请注意,解析a
必须包含在try
部分中——这是实际触发失败的地方。
为了可视化差异,让我们看一下相同的场景,但sepTry
改为:
...
a [b b a] b b b c b c b c b
成功!如果可能的话,让我们试着再买一个
a b b a ![b b] b c b c b c b
好的,我找到了另一个
bb
,所以顺序继续。解析a
a b b a !b b [b] c b c b c b
不是我所期望的。返回失败并将光标移到后面的感叹号。
a b b a ![]b b b c b c b c b
解析失败
bba
,解析序列完成。解析bbb
a b b a [b b b] c b c b c b
成功!
在您的情况下,每个Sample
解析器将尝试Sample
在它们之后读取 2 个换行符,或者在失败的情况下读取 3 个换行符并继续MaskedOperation
s
推荐阅读
- cs50 - 我不断收到分段错误,我不知道为什么。我可能错误地使用 strcasecmp 函数,但我不确定
- swift - 如何在导航栏(Xcode)中将右栏按钮项放在彼此之上?
- amazon-web-services - 如何限制对 REST API 的访问以仅匹配用户的 ID?
- xamarin.forms - Xamarin Forms两个ListView垂直并排
- design-patterns - 如何在 Rust 中可变地使用堆栈上多个实例中的一个实例?
- c++ - 如何为多个队列设计出队算法
- python - 有没有一种方法可以让我的乒乓球根据它在球拍上的位置移动?游戏
- numpy - 如何在numpy数组的特定位置添加数字
- javascript - 如何从反应中的锚标签或链接标签中删除虚线?
- linux - 为什么我们在 Linux 命令中使用 -i?