В качестве отправной точки, самый простой ответ на вопрос «Как создать подпарсер» использует монадное связывание, аппликативное <*>
, альтернативное <|>
и комбинаторы, предоставляемые библиотекой.Предполагая, что каждая команда принадлежит одному типу (как в ответе Ханса Крюгера) и с произвольным числом столбцов, приведенный ниже может быть хорошим шаблоном.
import Text.Parsec
import Text.Parsec.Char
import Data.List(transpose)
cmdFileParser :: Parsec s u [[CommandType]]
cmdFileParser = sepBy sepParser cmdLineParser
where
sepParser = newline --From Text.Parsec.Char
cmdLineParser :: Parsec s u [CommandType]
cmdLineParser = sepBy sepParser cmdParser
where
sepParser = tab
cmdParser :: Parsec s u CommandType
cmdParser = parseCommand1
<|> parseCommand2
<|> parseCommand3
<|> etc
Затем, после анализа, транспонируйте[[CommandType]]
для группировки команд по столбцу
main = do
...
let ret = runParser cmdFileParser
"debug string telling what was parsed"
stringToParse
case ret of
Left e -> putStrLn "wasn't parsed"
Right cmds -> doSomethingWith (transpose cmds)
Я бы сказал, что вышеприведенный типичный подход.Есть варианты конечно.Например, если вы знаете, что должно быть только три столбца, вы могли бы вместо приведенных выше cmdLineParser
указать ниже
cmdLineParser :: Parsec s u (CommandType,CommandType,CommandType)
cmdLineParser = (\a b c -> (a,b,c)) <$> ct <*> ct <*> cmdParser
where
ct = cmdParser <* tab
Я бы сказал, что использование getState
является нетипичным.Когда я впервые начал использовать Parsec, я помню, что получил что-то похожее на то, что вы думаете после работы, но это было не красиво.Конечно, если вы действительно хотите просто вернуть строки, вы всегда можете проанализировать любой символ, кроме ваших новых строк и вкладок.
cmdParser :: Parsec s u String
cmdParser = many (noneOf "\n\t")
Хотя, будьте осторожны при использовании вышеупомянутого.Я был сожжен в моем использовании many
раньше, где это занимает слишком много или всегда удается.Так что я не уверен, что эта точная формулировка даст вам командную строку.Кроме того, если вы просто проанализируете эту команду как строку, а затем повторите команду в вашем main
, вы будете анализировать дважды!