2012-02-14 114 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