秒差距:停在空行
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
(这不仅特定于 many
:x <|> 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'
我想用 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
(这不仅特定于 many
:x <|> 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'