Meilleur moyen d’parsingr les parameters de ligne de commande?

Quelle est la meilleure façon d’parsingr les parameters de ligne de commande dans Scala? Personnellement, je préfère quelque chose de léger qui ne nécessite pas de pot externe.

En relation:

  • Bibliothèque Java pour l’parsing des parameters de ligne de commande?
  • Quelles sont les bibliothèques d’parsingurs de parameters pour C ++?
  • Meilleur moyen d’parsingr les arguments de ligne de commande en C #

Dans la plupart des cas, vous n’avez pas besoin d’un parsingur externe. La correspondance de Scala permet de consumr des arguments dans un style fonctionnel. Par exemple:

object MmlAlnApp { val usage = """ Usage: mmlaln [--min-size num] [--max-size num] filename """ def main(args: Array[Ssortingng]) { if (args.length == 0) println(usage) val arglist = args.toList type OptionMap = Map[Symbol, Any] def nextOption(map : OptionMap, list: List[Ssortingng]) : OptionMap = { def isSwitch(s : Ssortingng) = (s(0) == '-') list match { case Nil => map case "--max-size" :: value :: tail => nextOption(map ++ Map('maxsize -> value.toInt), tail) case "--min-size" :: value :: tail => nextOption(map ++ Map('minsize -> value.toInt), tail) case ssortingng :: opt2 :: tail if isSwitch(opt2) => nextOption(map ++ Map('infile -> ssortingng), list.tail) case ssortingng :: Nil => nextOption(map ++ Map('infile -> ssortingng), list.tail) case option :: tail => println("Unknown option "+option) exit(1) } } val options = nextOption(Map(),arglist) println(options) } } 

imprimera, par exemple:

 Map('infile -> test/data/paml-aln1.phy, 'maxsize -> 4, 'minsize -> 2) 

Cette version ne prend qu’un infile. Facile à améliorer (en utilisant une liste).

Notez également que cette approche permet la concaténation de plusieurs arguments de ligne de commande – même plus de deux!

scopt / scopt

 val parser = new scopt.OptionParser[Config]("scopt") { head("scopt", "3.x") opt[Int]('f', "foo") action { (x, c) => c.copy(foo = x) } text("foo is an integer property") opt[File]('o', "out") required() valueName("") action { (x, c) => c.copy(out = x) } text("out is a required file property") opt[(Ssortingng, Int)]("max") action { case ((k, v), c) => c.copy(libName = k, maxCount = v) } validate { x => if (x._2 > 0) success else failure("Value  must be >0") } keyValueName("", "") text("maximum count for ") opt[Unit]("verbose") action { (_, c) => c.copy(verbose = true) } text("verbose is a flag") note("some notes.\n") help("help") text("prints this usage text") arg[File]("...") unbounded() optional() action { (x, c) => c.copy(files = c.files :+ x) } text("optional unbounded args") cmd("update") action { (_, c) => c.copy(mode = "update") } text("update is a command.") children( opt[Unit]("not-keepalive") abbr("nk") action { (_, c) => c.copy(keepalive = false) } text("disable keepalive"), opt[Boolean]("xyz") action { (x, c) => c.copy(xyz = x) } text("xyz is a boolean property") ) } // parser.parse returns Option[C] parser.parse(args, Config()) map { config => // do stuff } getOrElse { // arguments are bad, usage message will have been displayed } 

Ce qui précède génère le texte d’utilisation suivant:

 scopt 3.x Usage: scopt [update] [options] [...] -f  | --foo  foo is an integer property -o  | --out  out is a required file property --max:= maximum count for  --verbose verbose is a flag some notes. --help prints this usage text ... optional unbounded args Command: update update is a command. -nk | --not-keepalive disable keepalive --xyz  xyz is a boolean property 

C’est ce que j’utilise actuellement. Utilisation propre sans trop de bagages. (Disclaimer: Je maintiens maintenant ce projet)

Je me rends compte que la question a été posée il y a quelque temps, mais j’ai pensé que cela pourrait aider certaines personnes, qui font des recherches sur Google (comme moi), et qui ont frappé cette page.

La coquille Saint-Jacques semble également très prometteuse.

Fonctionnalités (citation de la page github liée):

  • options de drapeau, à valeur unique et à valeurs multiples
  • Noms d’options courts de type POSIX (-a) avec regroupement (-abc)
  • Noms d’options longs de style GNU (–opt)
  • Arguments de propriété (-Dkey = valeur, -D clé1 = valeur clé2 = valeur)
  • Types d’options et de propriétés de type non-chaîne (avec convertisseurs extensibles)
  • Correspondance puissante sur les arguments finaux
  • Sous-commandes

Et un exemple de code (également de cette page Github):

 import org.rogach.scallop._; object Conf extends ScallopConf(List("-c","3","-E","fruit=apple","7.2")) { // all options that are applicable to builder (like description, default, etc) // are applicable here as well val count:ScallopOption[Int] = opt[Int]("count", descr = "count the trees", required = true) .map(1+) // also here work all standard Option methods - // evaluation is deferred to after option construction val properties = props[Ssortingng]('E') // types (:ScallopOption[Double]) can be omitted, here just for clarity val size:ScallopOption[Double] = trailArg[Double](required = false) } // that's it. Completely type-safe and convenient. Conf.count() should equal (4) Conf.properties("fruit") should equal (Some("apple")) Conf.size.get should equal (Some(7.2)) // passing into other functions def someInternalFunc(conf:Conf.type) { conf.count() should equal (4) } someInternalFunc(Conf) 

J’aime glisser sur des arguments pour des configurations relativement simples.

 var name = "" var port = 0 var ip = "" args.sliding(2, 2).toList.collect { case Array("--ip", argIP: Ssortingng) => ip = argIP case Array("--port", argPort: Ssortingng) => port = argPort.toInt case Array("--name", argName: Ssortingng) => name = argName } 

Ceci est en grande partie un clone sans vergogne de ma réponse à la question Java du même sujet . Il s’avère que JewelCLI est compatible avec Scala car il ne nécessite pas de méthodes de style JavaBean pour obtenir un nommage automatique des arguments.

JewelCLI est une bibliothèque Java compatible avec Scala pour l’parsing de ligne de commande qui génère un code propre . Il utilise des interfaces proxy configurées avec des annotations pour créer dynamicment une API de type sécurisé pour vos parameters de ligne de commande.

Un exemple d’interface de paramètre Person.scala :

 import uk.co.flamingpenguin.jewel.cli.Option trait Person { @Option def name: Ssortingng @Option def times: Int } 

Un exemple d’utilisation de l’interface de parameters Hello.scala :

 import uk.co.flamingpenguin.jewel.cli.CliFactory.parseArguments import uk.co.flamingpenguin.jewel.cli.ArgumentValidationException object Hello { def main(args: Array[Ssortingng]) { try { val person = parseArguments(classOf[Person], args:_*) for (i <- 1 to (person times)) println("Hello " + (person name)) } catch { case e: ArgumentValidationException => println(e getMessage) } } } 

Enregistrez des copies des fichiers ci-dessus dans un seul répertoire et téléchargez également le fichier JAR JewelCLI 0.6 dans ce répertoire.

Comstackz et exécutez l’exemple dans Bash sous Linux / Mac OS X / etc .:

 scalac -cp jewelcli-0.6.jar:. Person.scala Hello.scala scala -cp jewelcli-0.6.jar:. Hello --name="John Doe" --times=3 

Comstackz et exécutez l’exemple dans l’invite de commandes Windows:

 scalac -cp jewelcli-0.6.jar;. Person.scala Hello.scala scala -cp jewelcli-0.6.jar;. Hello --name="John Doe" --times=3 

L’exécution de l’exemple doit produire la sortie suivante:

 Hello John Doe Hello John Doe Hello John Doe 

Interface de ligne de commande Scala Toolkit (CLIST)

ici aussi le mien! (un peu tard dans le jeu cependant)

https://github.com/backuity/clist

Par opposition au scopt il est entièrement mutable … mais attendez! Cela nous donne une belle syntaxe:

 class Cat extends Command(description = "concatenate files and print on the standard output") { // type-safety: members are typed! so showAll is a Boolean var showAll = opt[Boolean](abbrev = "A", description = "equivalent to -vET") var numberNonblank = opt[Boolean](abbrev = "b", description = "number nonempty output lines, overrides -n") // files is a Seq[File] var files = args[Seq[File]](description = "files to concat") } 

Et un moyen simple de l’exécuter:

 Cli.parse(args).withCommand(new Cat) { case cat => println(cat.files) } 

Vous pouvez bien sûr faire beaucoup plus (multi-commandes, nombreuses options de configuration, …) et ne pas avoir de dépendance.

Je vais finir avec une sorte de trait distinctif, l’utilisation par défaut (assez souvent négligée pour les commandes multiples): clist

Je suis du monde de Java, j’aime bien args4j parce que sa spécification simple est plus lisible (grâce aux annotations) et produit une sortie bien formatée.

Voici mon exemple:

spécification

 import org.kohsuke.args4j.{CmdLineException, CmdLineParser, Option} object CliArgs { @Option(name = "-list", required = true, usage = "List of Nutch Segment(s) Part(s)") var pathsList: Ssortingng = null @Option(name = "-workdir", required = true, usage = "Work directory.") var workDir: Ssortingng = null @Option(name = "-master", usage = "Spark master url") var masterUrl: Ssortingng = "local[2]" } 

Parse

 //var args = "-listt in.txt -workdir out-2".split(" ") val parser = new CmdLineParser(CliArgs) try { parser.parseArgument(args.toList.asJava) } catch { case e: CmdLineException => print(s"Error:${e.getMessage}\n Usage:\n") parser.printUsage(System.out) System.exit(1) } println("workDir :" + CliArgs.workDir) println("listFile :" + CliArgs.pathsList) println("master :" + CliArgs.masterUrl) 

Sur des arguments non valides

 Error:Option "-list" is required Usage: -list VAL : List of Nutch Segment(s) Part(s) -master VAL : Spark master url (default: local[2]) -workdir VAL : Work directory. 

Il y a aussi JCommander (avertissement: je l’ai créé):

 object Main { object Args { @Parameter( names = Array("-f", "--file"), description = "File to load. Can be specified multiple times.") var file: java.util.List[Ssortingng] = null } def main(args: Array[Ssortingng]): Unit = { new JCommander(Args, args.toArray: _*) for (filename <- Args.file) { val f = new File(filename) printf("file: %s\n", f.getName) } } } 

scala-optparse-applicative

Je pense que scala-optparse-applicative est la bibliothèque d’parsing de ligne de commande la plus fonctionnelle de Scala.

https://github.com/bmjames/scala-optparse-applicative

J’ai aimé l’approche slide () de joslinm mais pas les vars mutables;) Voici donc une manière immuable de cette approche:

 case class AppArgs( seed1: Ssortingng, seed2: Ssortingng, ip: Ssortingng, port: Int ) object AppArgs { def empty = new AppArgs("", "", "", 0) } val args = Array[Ssortingng]( "--seed1", "akka.tcp://seed1", "--seed2", "akka.tcp://seed2", "--nodeip", "192.167.1.1", "--nodeport", "2551" ) val argsInstance = args.sliding(2, 1).toList.foldLeft(AppArgs.empty) { case (accumArgs, currArgs) => currArgs match { case Array("--seed1", seed1) => accumArgs.copy(seed1 = seed1) case Array("--seed2", seed2) => accumArgs.copy(seed2 = seed2) case Array("--nodeip", ip) => accumArgs.copy(ip = ip) case Array("--nodeport", port) => accumArgs.copy(port = port.toInt) case unknownArg => accumArgs // Do whatever you want for this case } } 

Je viens de trouver une bibliothèque complète d’parsing de ligne de commande dans le package scala.tools.cmd de scalac.

Voir http://www.assembla.com/code/scala-eclipse-toolchain/git/nodes/src/comstackr/scala/tools/cmd?rev=f59940622e32384b1e08939effd24e924a8ba8db

J’ai tenté de généraliser la solution de @pjotrp en saisissant une liste de symboles de touches de position requirejs, une carte d’indicateur -> symbole de clé et options par défaut:

 def parseOptions(args: List[Ssortingng], required: List[Symbol], optional: Map[Ssortingng, Symbol], options: Map[Symbol, Ssortingng]): Map[Symbol, Ssortingng] = { args match { // Empty list case Nil => options // Keyword arguments case key :: value :: tail if optional.get(key) != None => parseOptions(tail, required, optional, options ++ Map(optional(key) -> value)) // Positional arguments case value :: tail if required != Nil => parseOptions(tail, required.tail, optional, options ++ Map(required.head -> value)) // Exit if an unknown argument is received case _ => printf("unknown argument(s): %s\n", args.mkSsortingng(", ")) sys.exit(1) } } def main(sysargs Array[Ssortingng]) { // Required positional arguments by key in options val required = List('arg1, 'arg2) // Optional arguments by flag which map to a key in options val optional = Map("--flag1" -> 'flag1, "--flag2" -> 'flag2) // Default options that are passed in var defaultOptions = Map() // Parse options based on the command line args val options = parseOptions(sysargs.toList, required, optional, defaultOptions) } 

J’ai basé mon approche sur la meilleure réponse (de dave4420) et j’ai essayé de l’améliorer en la rendant plus générale.

Il retourne une Map[Ssortingng,Ssortingng] de tous les parameters de la ligne de commande. Vous pouvez interroger ce paramètre pour les parameters spécifiques souhaités (par exemple, en utilisant .contains ) ou convertir les valeurs dans les types souhaités (par exemple, en utilisant toInt ).

 def argsToOptionMap(args:Array[Ssortingng]):Map[Ssortingng,Ssortingng]= { def nextOption( argList:List[Ssortingng], map:Map[Ssortingng, Ssortingng] ) : Map[Ssortingng, Ssortingng] = { val pattern = "--(\\w+)".r // Selects Arg from --Arg val patternSwitch = "-(\\w+)".r // Selects Arg from -Arg argList match { case Nil => map case pattern(opt) :: value :: tail => nextOption( tail, map ++ Map(opt->value) ) case patternSwitch(opt) :: tail => nextOption( tail, map ++ Map(opt->null) ) case ssortingng :: Nil => map ++ Map(ssortingng->null) case option :: tail => { println("Unknown option:"+option) sys.exit(1) } } } nextOption(args.toList,Map()) } 

Exemple:

 val args=Array("--testing1","testing1","-a","-b","--c","d","test2") argsToOptionMap( args ) 

Donne:

 res0: Map[Ssortingng,Ssortingng] = Map(testing1 -> testing1, a -> null, b -> null, c -> d, test2 -> null) 

une autre bibliothèque: scarg

Voici un parsingur de ligne de commande Scala facile à utiliser. Il formate automatiquement le texte d’aide et convertit les arguments du commutateur en fonction du type souhaité. Les commutateurs courts de style POSIX et GNU sont pris en charge. Prend en charge les commutateurs avec les arguments requirejs, les arguments facultatifs et les arguments de valeurs multiples. Vous pouvez même spécifier la liste finie des valeurs acceptables pour un commutateur particulier. Les noms de commutateurs longs peuvent être abrégés sur la ligne de commande pour plus de commodité. Similaire à l’parsingur d’options dans la bibliothèque standard Ruby.

Je viens de créer mon énumération simple

 val args: Array[Ssortingng] = "-silent -samples 100 -silent".split(" +").toArray //> args : Array[Ssortingng] = Array(-silent, -samples, 100, -silent) object Opts extends Enumeration { class OptVal extends Val { override def toSsortingng = "-" + super.toSsortingng } val nopar, silent = new OptVal() { // boolean options def apply(): Boolean = args.contains(toSsortingng) } val samples, maxgen = new OptVal() { // integer options def apply(default: Int) = { val i = args.indexOf(toSsortingng) ; if (i == -1) default else args(i+1).toInt} def apply(): Int = apply(-1) } } Opts.nopar() //> res0: Boolean = false Opts.silent() //> res1: Boolean = true Opts.samples() //> res2: Int = 100 Opts.maxgen() //> res3: Int = -1 

Je comprends que cette solution présente deux failles majeures qui peuvent vous distraire: elle élimine la liberté (c.-à-d. La dépendance aux autres bibliothèques, que vous appréciez tant) et la redondance (principe DRY, vous ne tapez qu’une seule fois variable et élimine la seconde fois en tant que texte de ligne de commande).

Je suggère d’utiliser http://docopt.org/ . Il y a un scala-port mais l’implémentation Java https://github.com/docopt/docopt.java fonctionne bien et semble être mieux maintenue. Voici un exemple:

 import org.docopt.Docopt import scala.collection.JavaConversions._ import scala.collection.JavaConverters._ val doc = """ Usage: my_program [options]  Options: --sorted fancy sorting """.ssortingpMargin.sortingm //def args = "--sorted test.dat".split(" ").toList var results = new Docopt(doc). parse(args()). map {case(key, value)=>key ->value.toSsortingng} val inputFile = new File(results("")) val sorted = results("--sorted").toBoolean 

Comment parsingr les parameters sans dépendance externe. Bonne question! Vous pourriez être intéressé par picocli .

Picocli est spécifiquement conçu pour résoudre le problème posé dans la question: il s’agit d’un cadre d’parsing de ligne de commande dans un seul fichier, vous pouvez donc l’ inclure sous forme de source . Cela permet aux utilisateurs d’exécuter des applications basées sur picocli sans nécessiter picocli en tant que dépendance externe .

Cela fonctionne en annotant les champs afin que vous écriviez très peu de code. Résumé rapide:

  • Tout fortement typé – les options de ligne de commande ainsi que les parameters de position
  • Prise en charge des options courtes en cluster POSIX (il gère donc -xvfInputFile ainsi que -x -v -f InputFile )
  • Un modèle d’arité qui permet un nombre minimum, maximum et variable de parameters, par exemple "1..*" , "3..5"
  • API fluide et compacte pour minimiser le code client standard
  • Sous-commandes
  • Aide à l’utilisation des couleurs ANSI

Le message d’aide à l’utilisation est facile à personnaliser avec des annotations (sans programmation). Par exemple:

Message d'aide d'utilisation étendue ( source )

Je n’ai pas pu m’empêcher d’append une capture d’écran supplémentaire pour montrer le type d’utilisation des messages d’aide possibles. L’aide à l’utilisation est le visage de votre application, alors soyez créatif et amusez-vous!

démo picocli

Disclaimer: J’ai créé picocli. Feedback ou questions très bienvenues. Il est écrit en Java, mais laissez-moi savoir s’il y a un problème en utilisant scala et je vais essayer de le résoudre.

J’aime le look épuré de ce code … tiré d’une discussion ici: http://www.scala-lang.org/old/node/4380

 object ArgParser { val usage = """ Usage: parser [-v] [-f file] [-s sopt] ... Where: -v Run verbosely -f F Set input file to F -s S Set Show option to S """ var filename: Ssortingng = "" var showme: Ssortingng = "" var debug: Boolean = false val unknown = "(^-[^\\s])".r val pf: PartialFunction[List[Ssortingng], List[Ssortingng]] = { case "-v" :: tail => debug = true; tail case "-f" :: (arg: Ssortingng) :: tail => filename = arg; tail case "-s" :: (arg: Ssortingng) :: tail => showme = arg; tail case unknown(bad) :: tail => die("unknown argument " + bad + "\n" + usage) } def main(args: Array[Ssortingng]) { // if there are required args: if (args.length == 0) die() val arglist = args.toList val remainingopts = parseArgs(arglist,pf) println("debug=" + debug) println("showme=" + showme) println("filename=" + filename) println("remainingopts=" + remainingopts) } def parseArgs(args: List[Ssortingng], pf: PartialFunction[List[Ssortingng], List[Ssortingng]]): List[Ssortingng] = args match { case Nil => Nil case _ => if (pf isDefinedAt args) parseArgs(pf(args),pf) else args.head :: parseArgs(args.tail,pf) } def die(msg: Ssortingng = usage) = { println(msg) sys.exit(1) } } 

Je n’ai jamais aimé le rbuy comme parsingur d’options. La plupart des développeurs qui les utilisent n’écrivent jamais une page de manuel appropriée pour leurs scripts et se retrouvent avec de longues options de pages qui ne sont pas organisées correctement à cause de leur parsingur.

J’ai toujours préféré la façon de faire de Perl avec Getopt :: Long .

Je travaille sur une mise en œuvre de scala. La première API ressemble à ceci:

 def print_version() = () => println("version is 0.2") def main(args: Array[Ssortingng]) { val (options, remaining) = OptionParser.getOptions(args, Map( "-f|--flag" -> 'flag, "-s|--ssortingng=s" -> 'ssortingng, "-i|--int=i" -> 'int, "-f|--float=f" -> 'double, "-p|-procedure=p" -> { () => println("higher order function" } "-h=p" -> { () => print_synopsis() } "--help|--man=p" -> { () => launch_manpage() }, "--version=p" -> print_version, )) 

Donc, appeler le script comme ceci:

 $ script hello -f --ssortingng=myssortingng -i 7 --float 3.14 --p --version world -- --nothing 

Imprimerait:

 higher order function version is 0.2 

Et reviens:

 remaining = Array("hello", "world", "--nothing") options = Map('flag -> true, 'ssortingng -> "myssortingng", 'int -> 7, 'double -> 3.14) 

Le projet est hébergé dans github scala-getoptions .

Comme tout le monde a posté sa propre solution, voici la mienne, parce que je voulais quelque chose de plus facile à écrire pour l’utilisateur: https://gist.github.com/gwenzek/78355526e476e08bb34d

Le fichier contient un fichier de code, plus un fichier de test et un court exemple copié ici:

 import ***.ArgsOps._ object Example { val parser = ArgsOpsParser("--someInt|-i" -> 4, "--someFlag|-f", "--someWord" -> "hello") def main(args: Array[Ssortingng]){ val argsOps = parser <<| args val someInt : Int = argsOps("--someInt") val someFlag : Boolean = argsOps("--someFlag") val someWord : String = argsOps("--someWord") val otherArgs = argsOps.args foo(someWord, someInt, someFlag) } } 

Il n'y a pas d'options sophistiquées pour forcer une variable à être dans certaines limites, car je ne pense pas que l'parsingur soit le meilleur endroit pour le faire.

Remarque: vous pouvez avoir autant d’alias que vous le souhaitez pour une variable donnée.

Je vais m’emstackr. J’ai résolu cela avec une simple ligne de code. Mes arguments de ligne de commande ressemblent à ceci:

 input--hdfs:/path/to/myData/part-00199.avro output--hdfs:/path/toWrite/Data fileFormat--avro option1--5 

Cela crée un tableau via la fonctionnalité de ligne de commande native de Scala (à partir de l’application ou d’une méthode principale):

 Array("input--hdfs:/path/to/myData/part-00199.avro", "output--hdfs:/path/toWrite/Data","fileFormat--avro","option1--5") 

Je peux alors utiliser cette ligne pour parsingr le tableau args par défaut:

 val nArgs = args.map(x=>x.split("--")).map(y=>(y(0),y(1))).toMap 

Qui crée une carte avec des noms associés aux valeurs de ligne de commande:

 Map(input -> hdfs:/path/to/myData/part-00199.avro, output -> hdfs:/path/toWrite/Data, fileFormat -> avro, option1 -> 5) 

Je peux alors accéder aux valeurs des parameters nommés dans mon code et l’ordre dans lequel ils apparaissent sur la ligne de commande n’est plus pertinent. Je me rends compte que c’est assez simple et ne possède pas toutes les fonctionnalités avancées mentionnées ci-dessus mais semble être suffisant dans la plupart des cas, ne nécessite qu’une seule ligne de code et n’implique pas de dépendances externes.

Voici le mien 1-liner

  def optArg(prefix: Ssortingng) = args.drop(3).find { _.startsWith(prefix) }.map{_.replaceFirst(prefix, "")} def optSpecified(prefix: Ssortingng) = optArg(prefix) != None def optInt(prefix: Ssortingng, default: Int) = optArg(prefix).map(_.toInt).getOrElse(default) 

Il laisse tomber 3 arguments obligatoires et donne les options. Les entiers sont spécifiés comme l’ -Xmx notoire -Xmx java, conjointement avec le préfixe. Vous pouvez parsingr des binarys et des entiers aussi simples que

 val cacheEnabled = optSpecified("cacheOff") val memSize = optInt("-Xmx", 1000) 

Pas besoin d’importer quoi que ce soit.

C’est ce que j’ai cuisiné. Il retourne un tuple d’une carte et une liste. La liste est pour l’entrée, comme les noms de fichiers d’entrée. La carte est pour les commutateurs / options.

 val args = "--sw1 1 input_1 --sw2 --sw3 2 input_2 --sw4".split(" ") val (options, inputs) = OptParser.parse(args) 

reviendra

 options: Map[Symbol,Any] = Map('sw1 -> 1, 'sw2 -> true, 'sw3 -> 2, 'sw4 -> true) inputs: List[Symbol] = List('input_1, 'input_2) 

Les commutateurs peuvent être “–t” dont x sera mis à true ou “–x 10” x sera mis à “10”. Tout le rest finira dans la liste.

 object OptParser { val map: Map[Symbol, Any] = Map() val list: List[Symbol] = List() def parse(args: Array[Ssortingng]): (Map[Symbol, Any], List[Symbol]) = _parse(map, list, args.toList) private [this] def _parse(map: Map[Symbol, Any], list: List[Symbol], args: List[Ssortingng]): (Map[Symbol, Any], List[Symbol]) = { args match { case Nil => (map, list) case arg :: value :: tail if (arg.startsWith("--") && !value.startsWith("--")) => _parse(map ++ Map(Symbol(arg.subssortingng(2)) -> value), list, tail) case arg :: tail if (arg.startsWith("--")) => _parse(map ++ Map(Symbol(arg.subssortingng(2)) -> true), list, tail) case opt :: tail => _parse(map, list :+ Symbol(opt), tail) } } } 

freecli

 package freecli package examples package command import java.io.File import freecli.core.all._ import freecli.config.all._ import freecli.command.all._ object Git extends App { case class CommitConfig(all: Boolean, message: Ssortingng) val commitCommand = cmd("commit") { takesG[CommitConfig] { O.help --"help" :: flag --"all" -'a' -~ des("Add changes from all known files") :: O.ssortingng -'m' -~ req -~ des("Commit message") } :: runs[CommitConfig] { config => if (config.all) { println(s"Commited all ${config.message}!") } else { println(s"Commited ${config.message}!") } } } val rmCommand = cmd("rm") { takesG[File] { O.help --"help" :: file -~ des("File to remove from git") } :: runs[File] { f => println(s"Removed file ${f.getAbsolutePath} from git") } } val remoteCommand = cmd("remote") { takes(O.help --"help") :: cmd("add") { takesT { O.help --"help" :: ssortingng -~ des("Remote name") :: ssortingng -~ des("Remote url") } :: runs[(Ssortingng, Ssortingng)] { case (s, u) => println(s"Remote $s $u added") } } :: cmd("rm") { takesG[Ssortingng] { O.help --"help" :: ssortingng -~ des("Remote name") } :: runs[Ssortingng] { s => println(s"Remote $s removed") } } } val git = cmd("git", des("Version control system")) { takes(help --"help" :: version --"version" -~ value("v1.0")) :: commitCommand :: rmCommand :: remoteCommand } val res = runCommandOrFail(git)(args).run } 

Cela générera l’utilisation suivante:

Usage

Le monstre rapide et sale de l’homme pauvre pour parsingr les paires clé = valeur:

 def main(args: Array[Ssortingng]) { val cli = args.map(_.split("=") match { case Array(k, v) => k->v } ).toMap val saveAs = cli("saveAs") println(saveAs) }