解析在Haskell中列出的字符串

时间:2014-11-18 11:42:02

标签: parsing haskell

我想在Haskell中解析字符串列表,但我不知道如何正确编写它。 字符串结构是:

A [B [], C [D [], E []]]

它代表结构

A-+-B
  |
  `-C-+-D
      |
      `-E

想法? 谢谢!

1 个答案:

答案 0 :(得分:2)

在Haskell中解析时最好的选择几乎总是Parsec。这是一个例子。

import Text.ParserCombinators.Parsec

data Tree a = Tree [Tree a] | Leaf a deriving Show

parseLeaf :: Parser (Tree Char)
parseLeaf = noneOf "[]" >>= return.Leaf

parseNode :: Parser (Tree Char)
parseNode = do
    char '['
    a <- parseTree
    char ']'
    return (Tree a)

parseTree = many1 (parseLeaf <|> parseNode)

测试一下:

> parseTest parseTree "a[aa]"
 [Leaf 'a',Tree [Leaf 'a',Leaf 'a']]
> parseTest parseTree "a[aa]aaa"
 [Leaf 'a',Tree [Leaf 'a',Leaf 'a'],Leaf 'a',Leaf 'a',Leaf 'a']
> parseTest parseTree "a[aa[aaaaaa]]aaa"
 [Leaf 'a',Tree [Leaf 'a',Leaf 'a',Tree [Leaf 'a',Leaf 'a',Leaf 'a',Leaf 'a',Leaf 'a',Leaf 'a']],Leaf 'a',Leaf 'a',Leaf 'a']

这是它的工作原理。 Parsec中的解析器是monadic,因此支持通常的写法。 (您也可以在应用程序中编写解析器,您可以在其他地方查找如何执行此操作。)

我们从简单的数据结构开始

data Tree a = Tree [Tree a] | Leaf a deriving Show

这与你想要的并不完全相同,但由于我不完全确定你的语义是什么,所以我使用了这个例子。您应该能够根据您的目的进行调整。

然后我们需要为树的每个可能部分提供解析器。叶子很简单,它只是一个不是括号的东西:

parseLeaf :: Parser (Tree Char)
parseLeaf = noneOf "[]" >>= return.Leaf

请注意,这可能是用手写的

写出来的
parseLeaf = do
   a <- noneOf "[]"
   return (Leaf a)

然后要解析树的分支部分,我们需要解析左括号和右括号。在括号之间,我们可以再次拥有一棵树。

parseNode :: Parser (Tree Char)
parseNode = do
    char '['
    a <- parseTree
    char ']'
    return (Tree a)

那么parseTree是什么?它只是我们编写的任何一个解析器中的许多。 <|>运算符允许解析器选择任一解析器,无论哪个先解析正确。所以我们有

parseTree = many1 (parseLeaf <|> parseNode)

您应该能够根据您的目的进行调整。看起来您的结构可能更像这样:

data Structure a = Node (Structure a) a a | Leaf a

通过遵循相同的原则,找出每种可能性所需的解析器,然后将它们组合起来,您应该立即解析。

<强>更新

这是一个解析您询问的数据结构的非常快速和脏的版本。它不支持空格或逗号,但应该有助于演示基本原则。

data Tree = Tree Char [Tree] deriving Show

parseTree :: Parser Tree
parseTree = do
    character <- noneOf "[]"
    subtree   <- parseSubTree
    return $ Tree character subtree

parseSubTree :: Parser [Tree]
parseSubTree = do
    char '['
    trees <- many parseTree
    char ']'
    return trees

这是一个以相当简单的方式添加逗号和空格的版本。 parsec库中有许多有用的组合器可以简化和改进它,你应该自己研究它们。另请注意用于symbol快捷方式解析器定义的应用程序样式。许多人更喜欢解析器的应用风格,它可以更简洁,所以值得发现。

data Tree = Tree Char [Tree] deriving Show

symbol :: String -> Parser String
symbol s = string s <* spaces

parseTree :: Parser Tree
parseTree = do
    character <- noneOf "[]"
    spaces
    subtree <- parseSubTree
    return $ Tree character subtree

parseSubTree :: Parser [Tree]
parseSubTree = do
    symbol "["
    trees <- sepBy parseTree (symbol ",")
    symbol "]"
    return trees

这里有效:

> parseTest parseTree "A [ A [ B [ ] , C   [ ], D [ ] ] ] "
Tree 'A' [Tree 'A' [Tree 'B' [],Tree 'C' [],Tree 'D' []]]