In den meisten Fällen benötigen Sie keinen externen Parser. Der Mustervergleich von Scala ermöglicht das Konsumieren von Argumenten in einem funktionalen Stil. Beispielsweise:
object MmlAlnApp {
val usage = """
Usage: mmlaln [--min-size num] [--max-size num] filename
"""
def main(args: Array[String]) {
if (args.length == 0) println(usage)
val arglist = args.toList
type OptionMap = Map[Symbol, Any]
def nextOption(map : OptionMap, list: List[String]) : OptionMap = {
def isSwitch(s : String) = (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 string :: opt2 :: tail if isSwitch(opt2) =>
nextOption(map ++ Map('infile -> string), list.tail)
case string :: Nil => nextOption(map ++ Map('infile -> string), list.tail)
case option :: tail => println("Unknown option "+option)
exit(1)
}
}
val options = nextOption(Map(),arglist)
println(options)
}
}
druckt zum Beispiel:
Map('infile -> test/data/paml-aln1.phy, 'maxsize -> 4, 'minsize -> 2)
Diese Version benötigt nur eine Infile. Einfach zu verbessern (mithilfe einer Liste).
Beachten Sie auch, dass dieser Ansatz die Verkettung mehrerer Befehlszeilenargumente ermöglicht - sogar mehr als zwei!
nextOption
ist kein guter Name für die Funktion. Es ist eine Funktion, die eine Karte zurückgibt - die Tatsache, dass sie rekursiv ist, ist ein Implementierungsdetail. Es ist, als würde man einemax
Funktion für eine Sammlung schreiben und sienextMax
einfach aufrufen, weil man sie mit expliziter Rekursion geschrieben hat. Warum nennstoptionMap
du es nicht einfach ?listToOptionMap(lst:List[String])
mit der darinnextOption
definierten Funktion zu definieren, wobei eine letzte Zeile sagtreturn nextOption(Map(), lst)
. Trotzdem muss ich gestehen, dass ich in meiner Zeit viel ungeheuerlichere Abkürzungen gemacht habe als in dieser Antwort.exit(1)
möglicherweise seinsys.exit(1)
file
Parameter zu behandeln :case string :: tail => { if (isSwitch(string)) { println("Unknown option: " + string) sys.exit(1) } else nextOption(map ++ Map('files -> (string :: map('files).asInstanceOf[List[String]])), tail)
. Die Karte benötigt auch einen Standardwert vonNil
, dhval options = nextOption(Map() withDefaultValue Nil, args.toList)
. Was ich nicht mag, ist, dass ich zurückgreifen mussasInstanceOf
, weil dieOptionMap
Werte vom Typ sindAny
. Gibt es eine bessere Lösung?scopt / scopt
Das Obige generiert den folgenden Verwendungstext:
Dies ist, was ich derzeit benutze. Saubere Nutzung ohne zu viel Gepäck. (Haftungsausschluss: Ich pflege dieses Projekt jetzt)
quelle
Mir ist klar, dass die Frage vor einiger Zeit gestellt wurde, aber ich dachte, sie könnte einigen Leuten helfen, die herum googeln (wie ich), und diese Seite aufrufen.
Jakobsmuschel sieht auch ziemlich vielversprechend aus.
Features (Zitat von der verlinkten Github-Seite):
Und ein Beispielcode (auch von dieser Github-Seite):
quelle
(x, c) => c.copy(xyz = x)
in scoptIch mag es, über Argumente für relativ einfache Konfigurationen zu gleiten .
quelle
args.sliding(2, 2)
?var port = 0
?Befehlszeilenschnittstelle Scala Toolkit (CLIST)
hier ist auch meins! (allerdings etwas spät im Spiel)
https://github.com/backuity/clist
Im Gegensatz dazu ist
scopt
es völlig veränderlich ... aber warte! Das gibt uns eine ziemlich schöne Syntax:Und eine einfache Möglichkeit, es auszuführen:
Sie können natürlich viel mehr tun (Mehrfachbefehle, viele Konfigurationsoptionen, ...) und haben keine Abhängigkeit.
Ich werde mit einer Art Besonderheit abschließen, der Standardverwendung (die bei mehreren Befehlen häufig vernachlässigt wird):
quelle
Password
,Hex
...), dann können Sie diese nutzen können .Dies ist größtenteils ein schamloser Klon meiner Antwort auf die Java-Frage zum gleichen Thema . Es stellt sich heraus, dass JewelCLI Scala-freundlich ist, da keine JavaBean-Methoden erforderlich sind, um eine automatische Argumentbenennung zu erhalten.
JewelCLI ist eine Scala-freundliche Java-Bibliothek für die Befehlszeilenanalyse, die sauberen Code liefert . Es verwendet Proxied Interfaces Configured with Annotations, um dynamisch eine typsichere API für Ihre Befehlszeilenparameter zu erstellen.
Ein Beispiel für eine Parameterschnittstelle
Person.scala
:Ein Beispiel für die Verwendung der Parameterschnittstelle
Hello.scala
:Speichern Sie Kopien der oben genannten Dateien in einem einzigen Verzeichnis und laden Sie die JewelCLI 0.6-JAR ebenfalls in dieses Verzeichnis herunter .
Kompilieren Sie das Beispiel und führen Sie es in Bash unter Linux / Mac OS X / etc. Aus:
Kompilieren Sie das Beispiel und führen Sie es in der Windows-Eingabeaufforderung aus:
Das Ausführen des Beispiels sollte die folgende Ausgabe ergeben:
quelle
So analysieren Sie Parameter ohne externe Abhängigkeit. Gute Frage! Sie könnten an Picocli interessiert sein .
Picocli wurde speziell entwickelt, um das in der Frage gestellte Problem zu lösen: Es handelt sich um ein Befehlszeilen-Parsing-Framework in einer einzelnen Datei, sodass Sie es in Quellform aufnehmen können . Auf diese Weise können Benutzer Picocli-basierte Anwendungen ausführen, ohne Picocli als externe Abhängigkeit zu benötigen .
Es funktioniert durch Annotieren von Feldern, so dass Sie sehr wenig Code schreiben. Kurze Zusammenfassung:
<command> -xvfInputFile
auch<command> -x -v -f InputFile
)"1..*"
."3..5"
Die Verwendungshilfemeldung kann einfach mit Anmerkungen angepasst werden (ohne Programmierung). Beispielsweise:
( Quelle )
Ich konnte nicht widerstehen, einen weiteren Screenshot hinzuzufügen, um zu zeigen, welche Art von Verwendungshilfemeldungen möglich sind. Die Hilfe zur Verwendung ist das Gesicht Ihrer Anwendung. Seien Sie also kreativ und haben Sie Spaß!
Haftungsausschluss: Ich habe picocli erstellt. Feedback oder Fragen sind sehr willkommen. Es ist in Java geschrieben, aber lassen Sie mich wissen, wenn es Probleme bei der Verwendung in Scala gibt, und ich werde versuchen, es zu beheben.
quelle
Ich komme aus der Java-Welt und mag args4j, weil seine einfache Spezifikation (dank Anmerkungen) besser lesbar ist und eine gut formatierte Ausgabe erzeugt.
Hier ist mein Beispielausschnitt:
Spezifikation
Analysieren
Bei ungültigen Argumenten
quelle
Scala-Optparse-Applikativ
Ich denke, scala-optparse-applyative ist die funktionalste Befehlszeilen-Parser-Bibliothek in Scala.
https://github.com/bmjames/scala-optparse-applicative
quelle
examples
in der TestcodeEs gibt auch JCommander (Haftungsausschluss: Ich habe es erstellt):
quelle
Ich mochte den slide () -Ansatz von joslinm, nur nicht die veränderlichen vars;) Hier ist ein unveränderlicher Weg zu diesem Ansatz:
quelle
Ich habe gerade eine umfangreiche Befehlszeilen-Analysebibliothek im scala.tools.cmd-Paket von scalac gefunden.
Siehe http://www.assembla.com/code/scala-eclipse-toolchain/git/nodes/src/compiler/scala/tools/cmd?rev=f59940622e32384b1e08939effd24e924a8ba8db
quelle
Ich habe versucht, die Lösung von @ pjotrp zu verallgemeinern, indem ich eine Liste der erforderlichen Positionsschlüsselsymbole, eine Karte mit Flag -> Schlüsselsymbol und Standardoptionen aufgenommen habe:
quelle
-f|--flags
. Schauen Sie sich gist.github.com/DavidGamba/b3287d40b019e498982c an und aktualisieren Sie die Antwort, wenn Sie möchten . Ich werde wahrscheinlich jede Map und Option erstellen, damit Sie nur das, was Sie benötigen, mit benannten Argumenten übergeben können.Ich habe meinen Ansatz auf die Top-Antwort (von dave4420) gestützt und versucht, sie zu verbessern, indem ich sie allgemeiner gemacht habe.
Es gibt einen
Map[String,String]
aller Befehlszeilenparameter zurück. Sie können diesen nach den gewünschten Parametern abfragen (z. B. using.contains
) oder die Werte in die gewünschten Typen konvertieren (ztoInt
. B. using ).Beispiel:
Gibt:
quelle
eine andere Bibliothek: Scarg
quelle
Hier ist ein Scala-Befehlszeilenparser , der einfach zu verwenden ist. Der Hilfetext wird automatisch formatiert und die Switch-Argumente werden in den gewünschten Typ konvertiert. Es werden sowohl kurze POSIX- als auch lange GNU-Switches unterstützt. Unterstützt Switches mit erforderlichen Argumenten, optionalen Argumenten und Argumenten mit mehreren Werten. Sie können sogar die endliche Liste akzeptabler Werte für einen bestimmten Switch angeben. Lange Schalternamen können der Einfachheit halber in der Befehlszeile abgekürzt werden. Ähnlich dem Optionsparser in der Ruby-Standardbibliothek.
quelle
Ich habe Rubin-ähnliche Optionsparser noch nie gemocht. Die meisten Entwickler, die sie verwendet haben, schreiben nie eine richtige Manpage für ihre Skripte und haben am Ende Seitenoptionen, die aufgrund ihres Parsers nicht richtig organisiert sind.
Ich habe Perls Art, Dinge mit Perls Getopt :: Long zu tun, immer bevorzugt .
Ich arbeite an einer Scala-Implementierung. Die frühe API sieht ungefähr so aus:
Also so anrufen
script
:Würde drucken:
Und zurück:
Das Projekt wird in Github Scala-Getoptions gehostet .
quelle
Ich habe gerade meine einfache Aufzählung erstellt
Ich verstehe, dass die Lösung zwei Hauptmängel aufweist, die Sie ablenken können: Sie beseitigt die Freiheit (dh die Abhängigkeit von anderen Bibliotheken, die Sie so sehr schätzen) und die Redundanz (das DRY-Prinzip, Sie geben den Optionsnamen nur einmal als Scala-Programm ein Variable und entfernen Sie es zum zweiten Mal als Befehlszeilentext eingegeben).
quelle
Ich würde vorschlagen, http://docopt.org/ zu verwenden . Es gibt einen Scala-Port, aber die Java-Implementierung https://github.com/docopt/docopt.java funktioniert einwandfrei und scheint besser gewartet zu werden. Hier ist ein Beispiel:
quelle
Das habe ich gekocht. Es gibt ein Tupel einer Karte und eine Liste zurück. Die Liste dient zur Eingabe, ebenso wie die Namen der Eingabedateien. Karte ist für Schalter / Optionen.
wird zurückkehren
Schalter können "--t" sein, wobei x auf true gesetzt wird, oder "--x 10", wobei x auf "10" gesetzt wird. Alles andere wird in der Liste landen.
quelle
Ich mag das saubere Aussehen dieses Codes ... aus einer Diskussion hier: http://www.scala-lang.org/old/node/4380
quelle
Da jeder hier seine eigene Lösung gepostet hat, gehört sie mir, weil ich etwas wollte, das für den Benutzer einfacher zu schreiben ist: https://gist.github.com/gwenzek/78355526e476e08bb34d
Das Wesentliche enthält eine Codedatei sowie eine Testdatei und ein kurzes Beispiel, das hier kopiert wurde:
Es gibt keine ausgefallenen Optionen, um eine Variable in bestimmten Grenzen zu erzwingen, da ich nicht der Meinung bin, dass der Parser der beste Ort dafür ist.
Hinweis: Sie können für eine bestimmte Variable so viel Alias haben, wie Sie möchten.
quelle
Ich werde mich anhäufen. Ich habe dies mit einer einfachen Codezeile gelöst. Meine Befehlszeilenargumente sehen folgendermaßen aus:
Dadurch wird ein Array über die native Befehlszeilenfunktionalität von Scala erstellt (entweder über eine App oder eine Hauptmethode):
Ich kann dann diese Zeile verwenden, um das Standardargumentarray zu analysieren:
Dadurch wird eine Karte mit Namen erstellt, die den Befehlszeilenwerten zugeordnet sind:
Ich kann dann auf die Werte der benannten Parameter in meinem Code zugreifen und die Reihenfolge, in der sie in der Befehlszeile angezeigt werden, ist nicht mehr relevant. Mir ist klar, dass dies ziemlich einfach ist und nicht alle oben genannten erweiterten Funktionen bietet, aber in den meisten Fällen ausreichend zu sein scheint, nur eine Codezeile benötigt und keine externen Abhängigkeiten beinhaltet.
quelle
Hier ist mein 1-Liner
Es werden 3 obligatorische Argumente gelöscht und die Optionen angegeben. Ganzzahlen werden wie die berüchtigte
-Xmx<size>
Java-Option zusammen mit dem Präfix angegeben. Sie können Binärdateien und Ganzzahlen so einfach wie analysierenSie müssen nichts importieren.
quelle
Der schnelle und schmutzige Einzeiler des armen Mannes zum Parsen von Schlüssel-Wert-Paaren:
quelle
freecli
Dies erzeugt die folgende Verwendung:
Verwendung
quelle