W większości przypadków nie potrzebujesz zewnętrznego analizatora składni. Dopasowywanie wzorów Scali pozwala na spożywanie argumentów w funkcjonalnym stylu. Na przykład:
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)
}
}
wydrukuje na przykład:
Map('infile -> test/data/paml-aln1.phy, 'maxsize -> 4, 'minsize -> 2)
Ta wersja zajmuje tylko jeden plik infile. Łatwe do ulepszenia (przy użyciu listy).
Zauważ też, że takie podejście pozwala na połączenie wielu argumentów wiersza poleceń - nawet więcej niż dwóch!
nextOption
nie jest dobrą nazwą dla tej funkcji. Jest to funkcja, która zwraca mapę - fakt, że jest ona rekurencyjna, jest szczegółem implementacji. To tak, jakby napisaćmax
funkcję dla kolekcji i nazwać jąnextMax
po prostu dlatego, że napisałeś ją z jawną rekurencją. Dlaczego nie po prostu to nazwaćoptionMap
?listToOptionMap(lst:List[String])
za pomocąnextOption
zdefiniowanej w tym celu funkcji , z końcowym wierszemreturn nextOption(Map(), lst)
. To powiedziawszy, muszę wyznać, że w swoim czasie poczyniłem o wiele bardziej skandaliczne skróty niż w tej odpowiedzi.exit(1)
może wymagaćsys.exit(1)
file
parametrów: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)
. Mapa potrzebuje również wartości domyślnejNil
, tjval options = nextOption(Map() withDefaultValue Nil, args.toList)
. Nie podoba mi się to, że muszę się uciekaćasInstanceOf
, ponieważOptionMap
wartości są typoweAny
. Czy jest lepsze rozwiązanie?scopt / scopt
Powyższe generuje następujący tekst użycia:
Tego właśnie używam. Czyste użytkowanie bez nadmiernego bagażu. (Oświadczenie: Teraz utrzymuję ten projekt)
źródło
Zdaję sobie sprawę, że pytanie zostało zadane jakiś czas temu, ale pomyślałem, że może to pomóc niektórym osobom, które googlują wokół (jak ja), i wejść na tę stronę.
Przegrzebek wygląda również dość obiecująco.
Funkcje (cytat z połączonej strony github):
I przykładowy kod (również z tej strony Github):
źródło
(x, c) => c.copy(xyz = x)
w scoptLubię przesuwać argumenty w przypadku stosunkowo prostych konfiguracji.
źródło
args.sliding(2, 2)
?var port = 0
?Interfejs wiersza polecenia Scala Toolkit (CLIST)
tu też jest moje! (nieco później w grze)
https://github.com/backuity/clist
W przeciwieństwie do
scopt
tego jest całkowicie zmienny ... ale czekaj! To daje nam całkiem niezłą składnię:I prosty sposób na uruchomienie:
Możesz oczywiście zrobić znacznie więcej (wiele poleceń, wiele opcji konfiguracji, ...) i nie ma zależności.
Zakończę pewnego rodzaju charakterystyczną funkcją, domyślnym użyciem (dość często zaniedbywanym w przypadku wielu poleceń):
źródło
Password
,Hex
...), a następnie można wykorzystać to.Jest to w dużej mierze bezwstydny klon mojej odpowiedzi na pytanie Java na ten sam temat . Okazuje się, że JewelCLI jest przyjazny dla Scali, ponieważ nie wymaga metod JavaBean do automatycznego nazywania argumentów.
JewelCLI to przyjazna dla Scali biblioteka Java do analizowania wiersza poleceń, która daje czysty kod . Wykorzystuje interfejsy proxy skonfigurowane z adnotacjami, aby dynamicznie budować bezpieczny interfejs API typu dla parametrów wiersza poleceń.
Przykładowy interfejs parametrów
Person.scala
:Przykładowe użycie interfejsu parametrów
Hello.scala
:Zapisz kopie powyższych plików w jednym katalogu i pobierz również JAR JewelCLI 0.6 .
Skompiluj i uruchom przykład w Bash na Linux / Mac OS X / etc .:
Skompiluj i uruchom przykład w wierszu polecenia systemu Windows:
Uruchomienie przykładu powinno dać następujące wyniki:
źródło
Jak parsować parametry bez zewnętrznej zależności. Świetne pytanie! Możesz być zainteresowany Picocli .
Picocli jest specjalnie zaprojektowany, aby rozwiązać problem zadany w pytaniu: jest strukturą parsowania wiersza poleceń w jednym pliku, więc możesz dołączyć go w formie źródłowej . Dzięki temu użytkownicy mogą uruchamiać aplikacje oparte na Picocli, nie wymagając Picocli jako zewnętrznej zależności .
Działa poprzez adnotacje pól, dzięki czemu piszesz bardzo mało kodu. Szybkie podsumowanie:
<command> -xvfInputFile
a także<command> -x -v -f InputFile
)"1..*"
,"3..5"
Komunikat pomocy dotyczącej użytkowania można łatwo dostosować za pomocą adnotacji (bez programowania). Na przykład:
( źródło )
Nie mogłem się powstrzymać przed dodaniem jeszcze jednego zrzutu ekranu, aby pokazać, jakie komunikaty pomocy dotyczące użytkowania są możliwe. Pomoc dotycząca użytkowania jest obliczem Twojej aplikacji, więc bądź kreatywny i baw się dobrze!
Uwaga: Stworzyłem picocli. Informacje zwrotne lub pytania bardzo mile widziane. Jest napisany w Javie, ale daj mi znać, jeśli jest jakiś problem z użyciem go w scali, a ja postaram się rozwiązać.
źródło
Jestem ze świata Java, lubię args4j, ponieważ jego prosta specyfikacja jest bardziej czytelna (dzięki adnotacjom) i zapewnia ładnie sformatowane dane wyjściowe.
Oto mój przykładowy fragment:
Specyfikacja
Analizować
W przypadku nieprawidłowych argumentów
źródło
Scala-Optparse-Applative
Myślę, że scala-optparse-application jest najbardziej funkcjonalną biblioteką analizatora składni wiersza poleceń w Scali.
https://github.com/bmjames/scala-optparse-applicative
źródło
examples
kod testowyJest też JCommander (oświadczenie: ja go stworzyłem):
źródło
Podobało mi się podejście Slide () joslinm, a nie zmienne zmienne;) Oto niezmienny sposób na to podejście:
źródło
Właśnie znalazłem obszerną bibliotekę parsowania wiersza poleceń w pakiecie scalala.tools.cmd.
Zobacz http://www.assembla.com/code/scala-eclipse-toolchain/git/nodes/src/compiler/scala/tools/cmd?rev=f59940622e32384b1e08939effd24e924a8ba8db
źródło
Podjąłem próbę uogólnienia rozwiązania @ pjotrp, biorąc listę wymaganych symboli kluczy pozycyjnych, mapę flagi -> symbol klucza i domyślne opcje:
źródło
-f|--flags
. Spójrz na gist.github.com/DavidGamba/b3287d40b019e498982c i prosimy o aktualizację odpowiedzi, jeśli Ci się spodoba. Prawdopodobnie wykonam każdą mapę i opcję, abyś mógł przekazać tylko to, czego potrzebujesz, z nazwanymi argumentami.Oparłem swoje podejście na najlepszej odpowiedzi (z dave4420) i próbowałem je poprawić, czyniąc je bardziej ogólnym.
Zwraca jeden
Map[String,String]
ze wszystkich parametrów wiersza poleceń. Możesz zapytać o określone parametry, które chcesz (np. Używając.contains
) lub przekonwertować wartości na żądane typy (np. UżywająctoInt
).Przykład:
Daje:
źródło
inna biblioteka: scarg
źródło
Oto prosty w użyciu parser linii poleceń scala . Automatycznie formatuje tekst pomocy i konwertuje argumenty przełącznika na pożądany typ. Obsługiwane są zarówno krótkie przełączniki POSIX, jak i długie przełączniki GNU. Obsługuje przełączniki z wymaganymi argumentami, argumentami opcjonalnymi i argumentami o wielu wartościach. Możesz nawet określić skończoną listę dopuszczalnych wartości dla konkretnego przełącznika. Długie nazwy przełączników można dla wygody skracać w wierszu poleceń. Podobne do parsera opcji w standardowej bibliotece Ruby.
źródło
Nigdy nie lubiłem parserów opcji podobnych do ruby. Większość programistów, którzy ich używali, nigdy nie pisze odpowiedniej strony podręcznika użytkownika dla swoich skryptów i kończy się na tym, że opcje stron nie są odpowiednio zorganizowane z powodu ich parsera.
Zawsze preferowałem sposób, w jaki Perl robi rzeczy z Peropt 's Getopt :: Long .
Pracuję nad jego wdrożeniem scala. Wczesne API wygląda mniej więcej tak:
Więc dzwonienie w
script
ten sposób:Wydrukowałby:
I wróć:
Projekt jest hostowany w github scala-getoptions .
źródło
Właśnie stworzyłem moje proste wyliczenie
Rozumiem, że rozwiązanie ma dwie główne wady, które mogą cię rozpraszać: eliminuje swobodę (tj. Zależność od innych bibliotek, które tak bardzo cenisz) i redundancję (zasada DRY, wpisujesz nazwę opcji tylko raz, jako program Scala zmienną i wyeliminuj ją po raz drugi wpisany jako tekst wiersza poleceń).
źródło
Sugerowałbym użyć http://docopt.org/ . Istnieje port Scala, ale implementacja Java https://github.com/docopt/docopt.java działa dobrze i wydaje się być lepiej utrzymana. Oto przykład:
źródło
Właśnie to ugotowałem. Zwraca krotkę mapy i listy. Lista służy do wprowadzania, podobnie jak nazwy plików wejściowych. Mapa dotyczy przełączników / opcji.
wróci
Przełącznikami może być „--t”, dla którego x zostanie ustawione na true, lub „--x 10”, dla którego x zostanie ustawione na „10”. Cała reszta znajdzie się na liście.
źródło
Lubię czysty wygląd tego kodu ... zaczerpniętego z dyskusji tutaj: http://www.scala-lang.org/old/node/4380
źródło
Jak wszyscy pisali, tutaj jest moje własne rozwiązanie, ponieważ chciałem napisać coś łatwiejszego dla użytkownika: https://gist.github.com/gwenzek/78355526e476e08bb34d
Treść zawiera plik kodu oraz plik testowy i krótki przykład skopiowany tutaj:
Nie ma wymyślnych opcji, aby zmusić zmienną do pewnego ograniczenia, ponieważ nie uważam, że parser jest najlepszym miejscem do tego.
Uwaga: możesz mieć tyle aliasów, ile chcesz dla danej zmiennej.
źródło
Idę na stos. Rozwiązałem to za pomocą prostej linii kodu. Moje argumenty wiersza poleceń wyglądają tak:
To tworzy tablicę za pomocą natywnej funkcjonalności wiersza poleceń Scali (z aplikacji lub głównej metody):
Następnie mogę użyć tego wiersza do przeanalizowania domyślnej tablicy args:
Który tworzy mapę z nazwami powiązanymi z wartościami wiersza poleceń:
Następnie mogę uzyskać dostęp do wartości nazwanych parametrów w moim kodzie, a kolejność, w jakiej pojawiają się w wierszu poleceń, nie jest już istotna. Zdaję sobie sprawę, że jest to dość proste i nie ma wszystkich zaawansowanych funkcji wymienionych powyżej, ale wydaje się wystarczające w większości przypadków, potrzebuje tylko jednego wiersza kodu i nie wymaga zewnętrznych zależności.
źródło
Oto mój 1-liniowy
Porzuca 3 obowiązkowe argumenty i podaje opcje. Liczby całkowite są określone podobnie jak notowana
-Xmx<size>
opcja java, łącznie z prefiksem. Możesz analizować pliki binarne i liczby całkowite tak proste jakNie musisz niczego importować.
źródło
Szybka i brudna jedna linijka biednego człowieka do analizy klucza = pary wartości:
źródło
freecli
Spowoduje to wygenerowanie następującego użycia:
Stosowanie
źródło