秒差距:停在空行

parsec: stopping at empty line

我想用 parsec 解决以下任务,尽管 splitOn "\n\n" 可能是更简单的答案。
我有一个像

这样的输入字符串
testInput = unlines ["ab", "cd", "", "e"] -- "ab\ncd\n\ne"

解析器在遇到空行时应停止。

我试过了

import Text.ParserCombinators.Parsec

inputFileP :: GenParser Char st String
inputFileP = many (lower <|> delimP)

delimP :: GenParser Char st Char
delimP = do
  x <- char '\n'
  notFollowedBy (char '\n')
  return x

失败 unexpected '\n'
为什么?
我的印象是 many x 解析 x 直到失败然后停止。

I was under the impression that many x parses x until it fails and then stops.

只有在 x 没有消耗任何输入的情况下失败时才会出现这种情况。如果 x 在消耗输入后失败,整个解析将失败,除非某处有 try (这不仅特定于 manyx <|> y 在这种情况下也会失败即使 y 会成功)。在您的情况下,delimP 在已经使用第一个 \n 之后在 notFollowedBy (char '\n') 上失败,因此整个解析失败。

要更改此行为,您需要使用 try 显式启用回溯,如下所示:

delimP = try $ do
  x <- char '\n'
  notFollowedBy (char '\n')
  return x

或者,您可以通过让 before 向前看两个字符来使 delimP 失败而不消耗任何输入(因此不需要尝试)匹配 \n:

delimP = do
  notFollowedBy (string "\n\n")
  char '\n'