我想在Haskell中解析字符串列表,但我不知道如何正确编写它。 字符串结构是:
A [B [], C [D [], E []]]
它代表结构
A-+-B
|
`-C-+-D
|
`-E
想法? 谢谢!
答案 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' []]]