Parsec用于平衡括号

时间:2018-04-13 20:39:11

标签: haskell

作为学习使用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;应用于接受空字符串的解析器。

1 个答案:

答案 0 :(得分:6)

使用{ braces }是正确的解决方案,但您需要首先摆脱many

问题在于,正如错误消息所示,optional可以匹配空字符串,问题是optional重复匹配,只要给定的解析器仍然可以找到比赛。如果解析器匹配空字符串,它将始终找到匹配项(空字符串),因此它永远不会停止循环。所以这是不允许的,以防止无限循环。

由于many已经匹配零次,因此不需要many,您可以摆脱它。