Разбор конкретной строки в Haskell - PullRequest
2 голосов
/ 14 февраля 2012

Я использую библиотеку parsec 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".

Кроме того, я хочу сохранить содержимое [[...]] в структуре данных.

Как сделатьВы решаете эту проблему?

1 Ответ

10 голосов
/ 14 февраля 2012

Вам нужно реструктурировать свой парсер. Вы используете комбинаторы в очень странных местах, и они все портят.

A var - это varName между "[[" и "]]". Итак, напишите, что:

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

A varName должен иметь какой-то формат (я не думаю, что вы хотите принять "% A¤% &", не так ли?), Поэтому вы должны сделать для этого парсер; но в случае, если это действительно может быть что угодно, просто сделайте это:

varName = many $ noneOf "]"

Тогда текст, содержащий переменные, представляет собой нечто с переменными, разделенными не переменными.

varText = someText *> var `sepEndBy` someText

... где someText - это что угодно, кроме '[':

someText = many $ noneOf "["

Вещи усложняются, если вы хотите, чтобы это было разбираемо:

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

Тогда вам нужен лучший парсер для varName и someText:

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.

...