2016-01-20 83 views
5

optparse-应用性选项我使用optparse-applicative和我想能够解析命令行参数如:具有多个值

$ ./program -a file1 file2 -b filea fileb 

即两个开关,这两者都可以采取多个参数。

所以,我有我的选择数据类型,看起来像这样:

data MyOptions = MyOptions { 
    aFiles :: [String] 
    , bFiles :: [String] } 

然后一个Parser这样的:

config :: Parser MyOptions 
config = MyOptions 
     <$> option (str >>= parseStringList) 
      (short 'a' <> long "aFiles") 
     <*> option (str >>= parseStringList) 
      (short 'b' <> long "bFiles") 

parseStringList :: Monad m => String -> m [String] 
parseStringList = return . words 

这种方法失败的,因为它会产生预期的结果当每个开关只提供一个参数时,但如果提供第二个参数,则会为第二个参数获得“无效参数”。我想知道是否可以假装我想要四个选项来组装它:布尔开关(即-a);字符串列表;另一个布尔开关(即-b);和另一个字符串列表。所以我改变了我的数据类型:

data MyOptions = MyOptions { 
    isA :: Bool 
    , aFiles :: [String] 
    , isB :: Bool 
    , bFiles :: [String] } 

,然后进行修改这样的解析器:使用manyargument组合算符,而不是一个字符串列表中的一个明确的解析器

config :: Parser MyOptions 
config = MyOptions 
     <$> switch 
      (short 'a' <> long "aFiles") 
     <*> many (argument str (metavar "FILE")) 
     <*> switch 
      (short 'b' <> long "bFiles") 
     <*> many (argument str (metavar "FILE")) 

这一次。

但是现在第一个many (argument str (metavar "FILE"))消耗全部的参数,包括那些在-b开关之后的参数。

那么我怎么写这个参数解析器?

回答

4

除了命令,optparse-applicative遵循getopts约定:命令行上的单个参数对应于单个选项参数。它甚至有点更加严格,因为getopts将允许在同一台交换机的多个选项:

./program-with-getopts -i input1 -i input2 -i input3 

所以没有“神奇”,可以帮助您立即使用你的程序像

./program-with-magic -a 1 2 3 -b foo bar crux 

自没有写出这样的想法,Options.Applicative.Parser;它也与POSIX conventions相抵触,其中选项只有一个参数或没有参数。

但是,可以从两个方面解决这个问题:无论是在getopts使用-a几次,因为你会的,或者告诉用户使用引号:

./program-as-above -a "1 2 3" -b "foo bar crux" 
# works already with your program! 

为了能够多次使用的选项您必须使用many(如果它们是可选的)或some(如果它们不是)。你甚至可以结合这两种型号:

multiString desc = concat <$> some single 
    where single = option (str >>= parseStringList) desc 

config :: Parser MyOptions 
config = MyOptions 
    <$> multiString (short 'a' <> long "aFiles" <> help "Use quotes/multiple") 
    <*> multiString (short 'b' <> long "bFiles" <> help "Use quotes/multiple") 

它使您能够使用

./program-with-posix-style -a 1 -a "2 3" -b foo -b "foo bar" 

但是,我知道任何解析库不支持你提出的风格,因为自由参数的位置将是暧昧。如果你真的想使用-a 1 2 3 -b foo bar crux,你必须自己解析参数。

+0

但是,如果'-a'的参数被限制为不以'-'开头,那么自由参数不会含糊不清。 – rampion