作为学习使用Parsec的练习,我正在编写一个验证平衡括号的解析器。我只担心对()
,[]
和{}
,但无法让我的解析器处理第一个中的多个括号组。
我正在对来自exercism.io的the bracket-push exercise提取的一些测试用例进行测试,但值得注意的边缘情况是:
isBalanced "" = True
isBalanced "(some[nonsense]with)brackets" = True
isBalanced "}{" = False -- reversed brackets no good.
isBalanced "{}}" = False -- extra ending brackets no good either.
我的解析器看起来像:
import Text.Parsec
import Text.Parsec.Char
hasMatchingBrackets = go >> eof
where
go = skipMany (noneOf "[{()}]")
>> optional (
between (char '(') (char ')') go
<|> between (char '{') (char '}') go
<|> between (char '[') (char ']') go )
>> skipMany (noneOf "[{()}]")
isBalanced :: String -> Bool
isBalanced xs = case parse hasMatchingBrackets "isBalanced" xs of
Right _ -> True
Left _ -> False
我的解析器as-is适用于上述所有情况,但是应该传递的以下测试用例不会
isBalanced "([{}({}[])])" = True -- Fails with the parser above!
我已将此问题确定为between
的替换,只允许在一对括号中出现一次go
,而[{}(...
中的开放式填充为2,但我不确定如何解决它。我尝试在skipMany1
前面打go
来阅读
between (char '(') (char ')') (skipMany1 go)
<|> ...etc
但是我收到了错误:
***例外:Text.ParserCombinators.Parsec.Prim.many:combinator&#39;很多&#39;应用于接受空字符串的解析器。
答案 0 :(得分:6)
使用{ braces }
是正确的解决方案,但您需要首先摆脱many
。
问题在于,正如错误消息所示,optional
可以匹配空字符串,问题是optional
重复匹配,只要给定的解析器仍然可以找到比赛。如果解析器匹配空字符串,它将始终找到匹配项(空字符串),因此它永远不会停止循环。所以这是不允许的,以防止无限循环。
由于many
已经匹配零次,因此不需要many
,您可以摆脱它。