2012-02-14 117 views
2

我正在使用parsec Haskell库。解析Haskell中的特定字符串

我想解析以下形式的字符串:

[[v1]][[v2]] 

xyz[[v1]][[v2]] 

[[v1]]xyz[[v2]] 

我只感兴趣收集的值v1和v2,而这些存储的数据结构。

我试着用下面的代码:

import Text.ParserCombinators.Parsec 

quantifiedVars = sepEndBy var (string "]]") 
var = between (string "[[") (string "") (many (noneOf "]]")) 

parseSL :: String -> Either ParseError [String] 
parseSL input = parse quantifiedVars "(unknown)" input 

main = do { 
    c <- getContents; 
    case parse quantifiedVars "(stdin)" c of { 
     Left e -> do { putStrLn "Error parsing input:"; print e; }; 
     Right r -> do{ putStrLn "ok"; mapM_ print r; }; 
    } 
} 

这样,如果输入的是"[[v1]][[v2]]"程序工作正常,返回下面的输出:

"v1" 

"v2" 

如果输入"xyz[[v1]][[v2]]"的程序不起作用。特别是,我只想要[[...]]中包含的内容,而忽略了"xyz"

另外,我想将[[...]]的内容存储在数据结构中。

你如何解决这个问题?

+0

所以你想跳过任何没有用[['和']]分隔的东西吗? ''“xyz [[v1]] [[v2]]”''和'“[[v1]] xyz [[v2]]”'都会产生'[“v1”,“v2”]'? – 2012-02-14 14:43:14

+0

它看起来像正则表达式的简单任务。像\\ [\\ [([^]] +)\\] \\]' – Yuras 2012-02-14 22:14:31

回答

10

您需要重构解析器。你在非常奇怪的位置使用组合器,他们搞砸了。

A var是“[[”和“]]”之间的varName。所以,写:

var = between (string "[[") (string "]]") varName 

一个varName应该有某种形式的(我不认为你要接受“%澶%&”,你呢?),因此你应该做一个解析器为了那个原因;但如果它真的可以是任何东西,只是这样做:

varName = many $ noneOf "]" 

然后,将含有瓦尔文本,是一些与非瓦尔分离瓦尔。

varText = someText *> var `sepEndBy` someText 

...其中someText是除外 '[' 什么:

someText = many $ noneOf "[" 
如果你想这是解析的

事情变得更加复杂:

bla bla [ bla bla [[somevar]blabla]] 

然后,你需要一个更好的解析器varNamesomeText

varName = concat <$> many (try incompleteTerminator <|> many1 (noneOf "]")) 

-- Parses e.g. "]a" 
incompleteTerminator = (\ a b -> [a, b]) <$> char ']' <*> noneOf "]" 

someText = concat <$> many (try incompleteInitiator <|> many1 (noneOf "[")) 

-- Parses e.g. "[b" 
incompleteInitiator = (\ a b -> [a, b]) <$> char '[' <*> noneOf "[" 

PS(<*>),(*>)(<$>)来自Control.Applicative

+0

亲爱的dflemstr,谢谢你的回答非常详细。我试图实现你的解决方案,但我有一个模糊的问题导入库“Control.Applicative”与“Text.ParserCombinators.Parsec”一起。特别是“模糊的发生”多“...”“模糊的发生”<|>'...“。所以,我试图使用“隐藏((<|>),很多)”但ghc返回一个新的错误。你怎么解决这个问题?谢谢! – kafka 2012-02-24 09:46:04

+1

这就是我的方式;你可以尝试'导入Control.Applicative((<*>),(*>),(<$>))'。 – dflemstr 2012-02-24 10:59:47