Haskell

40行Haskell代码的命令行参数解析器

2018-07-22  本文已影响1人  DarkBubble

40行Haskell代码的命令行解析器

第一步:定义选项结果的数据类型

为了简单起见,考虑三种情况:

  1. 独立选项:即没有任何先导符号,独立存在的选项。
  2. 开关选项:选项即自身,表示开启或者关闭某个功能。
  3. 带值选项:选项是前导符号加上后面的一个参数,表示取一个值(按字符串)

例子:

program -i input.txt -o output.txt s.log -k -v 

我们使用Haskell的代数数据类型(ADT)定义上述选项:

data CmdOptionResult = Standalone   {                  value :: String }
                     | OptionSwitch { name  :: String, flag  :: Bool   }
                     | OptionValue  { name  :: String, value :: String } deriving(Eq, Show, Read)

第二步:基本的解析器

parseSwitch _ [] = (Nothing, [])
parseSwitch (sname, lname) args@(arg:as)
    = if arg == lname || arg == sname
      then (Just (OptionSwitch lname True), as)
      else (Nothing, args)
parseValue _ [] = (Nothing, [])
parseValue (sname, lname) args@(arg:as)
    = if arg == lname || arg == sname
      then (Just (OptionValue lname (head as)), tail as)
      else (Nothing, args)

解析器组合子

parser1 <|> parser2
    = (\as -> let (v1, s1) = parser1 as
                  (v2, s2) = parser2 as
              in  if v1 /= Nothing
                  then (v1, s1)
                  else (v2, s2))
aggregate ps = foldl1 (<|>) ps
repeat ps = let parser = aggregate ps
                fromJust (Just x) = x
            in  \args -> let (v, s) = parser args
                         in  if args == []
                             then []
                             else if v == Nothing --  match failed, so it is a standalone option value
                                  then (Standalone (head args)):(Util.CmdParser.repeat ps (tail args))

例子

parser_lst_example = [ parseSwitch ("-v", "--verbose")
                     , parseValue  ("-i", "--input")
                     , parseValue  ("-o", "--output")
                     , parseValue  ("-m", "--mode")
                     , parseSwitch ("-h", "--help") ]

parser_example = Util.CmdParser.repeat parser_lst_example

args_example_1 = ["-i", "input.txt", "--output", "output.txt", "-v", "-m", "1"]
args_example_2 = ["-h"]
parser_example args_example_1
[OptionValue {name = "--input", value = "input.txt"},OptionValue {name = "--output", value = "output.txt"},OptionSwitch {name = "--verbose", flag = True},OptionValue {name = "--mode", value = "1"}]
*Util.CmdParser> parser_example args_example_2
[OptionSwitch {name = "--help", flag = True}]
上一篇 下一篇

猜你喜欢

热点阅读