option=value
-SyntaxFügen Sie einfach argparse.hpp hinzu und schon kann es losgehen.
# include < argparse/argparse.hpp >
Um mit dem Parsen von Befehlszeilenargumenten zu beginnen, erstellen Sie einen ArgumentParser
.
argparse::ArgumentParser program ( " program_name " );
HINWEIS: Es gibt ein optionales zweites Argument für den ArgumentParser
, das die Programmversion angibt. Beispiel: argparse::ArgumentParser program("libfoo", "1.9.0");
HINWEIS: Es gibt optionale dritte und vierte Argumente für den ArgumentParser
, die Standardargumente steuern. Beispiel: argparse::ArgumentParser program("libfoo", "1.9.0", default_arguments::help, false);
Siehe Standardargumente unten.
Um ein neues Argument hinzuzufügen, rufen Sie einfach .add_argument(...)
auf. Sie können eine unterschiedliche Liste von Argumentnamen bereitstellen, die Sie gruppieren möchten, z. B. -v
und --verbose
program.add_argument( " foo " );
program.add_argument( " -v " , " --verbose " ); // parameter packing
Argparse unterstützt eine Vielzahl von Argumenttypen, darunter Positionsargumente, optionale und zusammengesetzte Argumente. Unten sehen Sie, wie Sie jeden dieser Typen konfigurieren:
Hier ist ein Beispiel für ein Positionsargument :
# include < argparse/argparse.hpp >
int main ( int argc, char *argv[]) {
argparse::ArgumentParser program ( " program_name " );
program. add_argument ( " square " )
. help ( " display the square of a given integer " )
. scan < ' i ' , int >();
try {
program. parse_args (argc, argv);
}
catch ( const std:: exception & err) {
std::cerr << err. what () << std::endl;
std::cerr << program;
return 1 ;
}
auto input = program. get < int >( " square " );
std::cout << (input * input) << std::endl;
return 0 ;
}
Und den Code ausführen:
foo@bar:/home/dev/ $ ./main 15
225
Folgendes passiert:
add_argument()
wird angegeben, welche Befehlszeilenoptionen das Programm akzeptieren möchte. In diesem Fall habe ich es quadratisch genannt, damit es seiner Funktion entspricht..scan
, um Benutzereingaben in eine Ganzzahl umzuwandeln.parser.get<T>(key)
können wir den vom Parser für ein bestimmtes Argument gespeicherten Wert abrufen. Schauen wir uns nun optionale Argumente an. Optionale Argumente beginnen mit -
oder --
, z. B. --verbose
oder -a
. Optionale Argumente können an einer beliebigen Stelle in der Eingabesequenz platziert werden.
argparse::ArgumentParser program ( " test " );
program.add_argument( " --verbose " )
.help( " increase output verbosity " )
.default_value( false )
.implicit_value( true );
try {
program. parse_args (argc, argv);
}
catch ( const std:: exception & err) {
std::cerr << err. what () << std::endl;
std::cerr << program;
std::exit ( 1 );
}
if (program[ " --verbose " ] == true ) {
std::cout << " Verbosity enabled " << std::endl;
}
foo@bar:/home/dev/ $ ./main --verbose
Verbosity enabled
Folgendes passiert:
--verbose
ausgeführt wird. Beachten Sie, dass bei Verwendung von .default_value(false)
der Wert des optionalen Arguments automatisch auf false gesetzt wird, wenn es nicht verwendet wird..implicit_value(true)
gibt der Benutzer an, dass es sich bei dieser Option eher um ein Flag als um etwas handelt, das einen Wert erfordert. Wenn der Benutzer die Option --verbose angibt, wird ihr Wert auf true gesetzt. Beim Definieren von Flag-Argumenten können Sie die Abkürzung flag()
verwenden, die mit default_value(false).implicit_value(true)
identisch ist.
argparse::ArgumentParser program ( " test " );
program.add_argument( " --verbose " )
.help( " increase output verbosity " )
.flag();
try {
program. parse_args (argc, argv);
}
catch ( const std:: exception & err) {
std::cerr << err. what () << std::endl;
std::cerr << program;
std::exit ( 1 );
}
if (program[ " --verbose " ] == true ) {
std::cout << " Verbosity enabled " << std::endl;
}
Es gibt Szenarien, in denen Sie ein optionales Argument als erforderlich festlegen möchten. Wie oben erläutert, beginnen optionale Argumente entweder mit -
oder --
. Sie können diese Art von Argumenten wie folgt als erforderlich festlegen:
program.add_argument( " -o " , " --output " )
.required()
.help( " specify the output file. " );
Wenn der Benutzer für diesen Parameter keinen Wert angibt, wird eine Ausnahme ausgelöst.
Alternativ können Sie einen Standardwert wie diesen angeben:
program.add_argument( " -o " , " --output " )
.default_value(std::string( " - " ))
.required()
.help( " specify the output file. " );
Wenn Sie das Vorhandensein eines optionalen Arguments benötigen, aber keinen guten Standardwert dafür haben, können Sie das Testen und den Zugriff auf das Argument wie folgt kombinieren:
if ( auto fn = program.present( " -o " )) {
do_something_with (*fn);
}
Ähnlich wie get
akzeptiert die present
Methode auch ein Vorlagenargument. Aber anstatt T
zurückzugeben, gibt parser.present<T>(key)
std::optional<T>
zurück, sodass der Rückgabewert gleich std::nullopt
, wenn der Benutzer keinen Wert für diesen Parameter angibt.
Wenn Sie wissen möchten, ob der Benutzer einen Wert für ein Argument angegeben hat, das einen .default_value
hat, prüfen Sie, ob das Argument .is_used()
.
program.add_argument( " --color " )
.default_value(std::string{ " orange " }) // might otherwise be type const char* leading to an error when trying program.get<std::string>
.help( " specify the cat's fur color " );
try {
program. parse_args (argc, argv); // Example: ./main --color orange
}
catch ( const std:: exception & err) {
std::cerr << err. what () << std::endl;
std::cerr << program;
std::exit ( 1 );
}
auto color = program.get<std::string>( " --color " ); // "orange"
auto explicit_color = program.is_used( " --color " ); // true, user provided orange
Möglicherweise möchten Sie die Wiederholung eines optionalen Arguments zulassen und alle Werte an einem Ort sammeln.
program.add_argument( " --color " )
.default_value<std::vector<std::string>>({ " orange " })
.append()
.help( " specify the cat's fur color " );
try {
program. parse_args (argc, argv); // Example: ./main --color red --color green --color blue
}
catch ( const std:: exception & err) {
std::cerr << err. what () << std::endl;
std::cerr << program;
std::exit ( 1 );
}
auto colors = program.get<std::vector<std::string>>( " --color " ); // {"red", "green", "blue"}
Beachten Sie, dass .default_value
einen expliziten Vorlagenparameter erhält, der dem Typ entspricht, den Sie .get
erhalten möchten.
Ein häufiges Muster besteht darin, ein Argument zu wiederholen, um einen größeren Wert anzuzeigen.
int verbosity = 0 ;
program.add_argument( " -V " , " --verbose " )
.action([&]( const auto &) { ++verbosity; })
.append()
.default_value( false )
.implicit_value( true )
.nargs( 0 );
program.parse_args(argc, argv); // Example: ./main -VVVV
std::cout << " verbose level: " << verbosity << std::endl; // verbose level: 4
Erstellen Sie eine sich gegenseitig ausschließende Gruppe mit program.add_mutually_exclusive_group(required = false)
. „argparse“ stellt sicher, dass nur eines der Argumente in der sich gegenseitig ausschließenden Gruppe in der Befehlszeile vorhanden war:
auto &group = program.add_mutually_exclusive_group();
group.add_argument( " --first " );
group.add_argument( " --second " );
mit der folgenden Verwendung führt zu einem Fehler:
foo@bar:/home/dev/ $ ./main --first 1 --second 2
Argument '--second VAR' not allowed with '--first VAR'
Die Funktion add_mutually_exclusive_group()
akzeptiert auch ein required
Argument, um anzugeben, dass mindestens eines der sich gegenseitig ausschließenden Argumente erforderlich ist:
auto &group = program.add_mutually_exclusive_group( true );
group.add_argument( " --first " );
group.add_argument( " --second " );
mit der folgenden Verwendung führt zu einem Fehler:
foo@bar:/home/dev/ $ ./main
One of the arguments '--first VAR' or '--second VAR' is required
Es ist möglich, Argumente an eine Variable zu binden, die ihren Wert speichert, als Alternative zum expliziten Aufruf von program.get<T>(arg_name)
oder program[arg_name]
Dies ist derzeit für Variablen vom Typ bool
implementiert (dies ruft implizit auch flag()
auf), int
, double
, std::string
, std::vector<std::string>
und std::vector<int>
. Wenn das Argument nicht in der Befehlszeile angegeben wird, wird der Standardwert (sofern festgelegt) in die Variable gesetzt.
bool flagvar = false ;
program.add_argument( " --flagvar " ).store_into(flagvar);
int intvar = 0 ;
program.add_argument( " --intvar " ).store_into(intvar);
double doublevar = 0 ;
program.add_argument( " --doublevar " ).store_into(doublevar);
std::string strvar;
program.add_argument( " --strvar " ).store_into(strvar);
std::vector<std::string> strvar_repeated;
program.add_argument( " --strvar-repeated " ).append().store_into(strvar_repeated);
std::vector<std::string> strvar_multi_valued;
program.add_argument( " --strvar-multi-valued " ).nargs( 2 ).store_into(strvar_multi_valued);
std::vector< int > intvar_repeated;
program.add_argument( " --intvar-repeated " ).append().store_into(intvar_repeated);
std::vector< int > intvar_multi_valued;
program.add_argument( " --intvar-multi-valued " ).nargs( 2 ).store_into(intvar_multi_valued);
Optionale Argumente beginnen mit -
. Kann argparse
mit negativen Zahlen umgehen? Die Antwort ist ja!
argparse::ArgumentParser program;
program.add_argument( " integer " )
.help( " Input number " )
.scan< ' i ' , int >();
program.add_argument( " floats " )
.help( " Vector of floats " )
.nargs( 4 )
.scan< ' g ' , float >();
try {
program. parse_args (argc, argv);
}
catch ( const std:: exception & err) {
std::cerr << err. what () << std::endl;
std::cerr << program;
std::exit ( 1 );
}
// Some code to print arguments
foo@bar:/home/dev/ $ ./main -5 -1.1 -3.1415 -3.1e2 -4.51329E3
integer : -5
floats : -1.1 -3.1415 -310 -4513.29
Wie Sie hier sehen können, unterstützt argparse
negative Ganzzahlen, negative Gleitkommazahlen und wissenschaftliche Notation.
argparse::ArgumentParser program ( " main " );
program.add_argument( " square " )
.help( " display the square of a given number " )
.scan< ' i ' , int >();
program.add_argument( " --verbose " )
.default_value( false )
.implicit_value( true );
try {
program. parse_args (argc, argv);
}
catch ( const std:: exception & err) {
std::cerr << err. what () << std::endl;
std::cerr << program;
std::exit ( 1 );
}
int input = program.get< int >( " square " );
if (program[ " --verbose " ] == true ) {
std::cout << " The square of " << input << " is " << (input * input) << std::endl;
}
else {
std::cout << (input * input) << std::endl;
}
foo@bar:/home/dev/ $ ./main 4
16
foo@bar:/home/dev/ $ ./main 4 --verbose
The square of 4 is 16
foo@bar:/home/dev/ $ ./main --verbose 4
The square of 4 is 16
std::cout << program
gibt eine Hilfemeldung aus, einschließlich der Programmnutzung und Informationen zu den beim ArgumentParser
registrierten Argumenten. Für das vorherige Beispiel ist hier die Standard-Hilfemeldung:
foo@bar:/home/dev/$ ./main --help
Usage: main [-h] [--verbose] square
Positional arguments:
square display the square of a given number
Optional arguments:
-h, --help shows help message and exits
-v, --version prints version information and exits
--verbose
Sie können die Hilfemeldung auch als Zeichenfolge über program.help().str()
erhalten.
ArgumentParser::add_description
fügt Text vor den detaillierten Argumentinformationen hinzu. ArgumentParser::add_epilog
fügt nach allen anderen Hilfeausgaben Text hinzu.
# include < argparse/argparse.hpp >
int main ( int argc, char *argv[]) {
argparse::ArgumentParser program ( " main " );
program. add_argument ( " thing " ). help ( " Thing to use. " ). metavar ( " THING " );
program. add_argument ( " --member " ). help ( " The alias for the member to pass to. " ). metavar ( " ALIAS " );
program. add_argument ( " --verbose " ). default_value ( false ). implicit_value ( true );
program. add_description ( " Forward a thing to the next member. " );
program. add_epilog ( " Possible things include betingalw, chiz, and res. " );
program. parse_args (argc, argv);
std::cout << program << std::endl;
}
Usage: main [-h] [--member ALIAS] [--verbose] THING
Forward a thing to the next member.
Positional arguments:
THING Thing to use.
Optional arguments:
-h, --help shows help message and exits
-v, --version prints version information and exits
--member ALIAS The alias for the member to pass to.
--verbose
Possible things include betingalw, chiz, and res.
ArgumentParser-Objekte verknüpfen normalerweise ein einzelnes Befehlszeilenargument mit einer einzelnen auszuführenden Aktion. Die .nargs
Datei ordnet einer einzelnen Aktion eine unterschiedliche Anzahl von Befehlszeilenargumenten zu. Bei Verwendung nargs(N)
werden N Argumente aus der Befehlszeile in einer Liste zusammengefasst.
argparse::ArgumentParser program ( " main " );
program.add_argument( " --input_files " )
.help( " The list of input files " )
.nargs( 2 );
try {
program. parse_args (argc, argv); // Example: ./main --input_files config.yml System.xml
}
catch ( const std:: exception & err) {
std::cerr << err. what () << std::endl;
std::cerr << program;
std::exit ( 1 );
}
auto files = program.get<std::vector<std::string>>( " --input_files " ); // {"config.yml", "System.xml"}
ArgumentParser.get<T>()
hat Spezialisierungen für std::vector
und std::list
. Daher funktioniert auch die folgende Variante .get<std::list>
.
auto files = program.get<std::list<std::string>>( " --input_files " ); // {"config.yml", "System.xml"}
Mit .scan
kann man aus Befehlszeilenargumenten schnell eine Liste gewünschter Werttypen erstellen. Hier ist ein Beispiel:
argparse::ArgumentParser program ( " main " );
program.add_argument( " --query_point " )
.help( " 3D query point " )
.nargs( 3 )
.default_value(std::vector< double >{ 0.0 , 0.0 , 0.0 })
.scan< ' g ' , double >();
try {
program. parse_args (argc, argv); // Example: ./main --query_point 3.5 4.7 9.2
}
catch ( const std:: exception & err) {
std::cerr << err. what () << std::endl;
std::cerr << program;
std::exit ( 1 );
}
auto query_point = program.get<std::vector< double >>( " --query_point " ); // {3.5, 4.7, 9.2}
Sie können mit .nargs
auch eine Liste von Argumenten variabler Länge erstellen. Nachfolgend finden Sie einige Beispiele.
program.add_argument( " --input_files " )
.nargs( 1 , 3 ); // This accepts 1 to 3 arguments.
Einige nützliche Muster sind in Python wie „?“, „*“, „+“ von argparse definiert.
program.add_argument( " --input_files " )
.nargs(argparse::nargs_pattern::any); // "*" in Python. This accepts any number of arguments including 0.
program.add_argument( " --input_files " )
.nargs(argparse::nargs_pattern::at_least_one); // "+" in Python. This accepts one or more number of arguments.
program.add_argument( " --input_files " )
.nargs(argparse::nargs_pattern::optional); // "?" in Python. This accepts an argument optionally.
Zusammengesetzte Argumente sind optionale Argumente, die kombiniert und als einzelnes Argument bereitgestellt werden. Beispiel: ps -aux
argparse::ArgumentParser program ( " test " );
program.add_argument( " -a " )
.default_value( false )
.implicit_value( true );
program.add_argument( " -b " )
.default_value( false )
.implicit_value( true );
program.add_argument( " -c " )
.nargs( 2 )
.default_value(std::vector< float >{ 0 . 0f , 0 . 0f })
.scan< ' g ' , float >();
try {
program. parse_args (argc, argv); // Example: ./main -abc 1.95 2.47
}
catch ( const std:: exception & err) {
std::cerr << err. what () << std::endl;
std::cerr << program;
std::exit ( 1 );
}
auto a = program.get< bool >( " -a " ); // true
auto b = program.get< bool >( " -b " ); // true
auto c = program.get<std::vector< float >>( " -c " ); // {1.95, 2.47}
// / Some code that prints parsed arguments
foo@bar:/home/dev/ $ ./main -ac 3.14 2.718
a = true
b = false
c = {3.14, 2.718}
foo@bar:/home/dev/ $ ./main -cb
a = false
b = true
c = {0.0, 0.0}
Folgendes passiert:
-a
, -b
und -c
.-a
und -b
sind Umschaltargumente.-c
erfordert 2 Gleitkommazahlen von der Befehlszeile.-abc
oder -bac
oder -cab
. Dies funktioniert nur mit kurzen, aus einem Zeichen bestehenden Argumentnamen.-a
und -b
werden wahr.-c
zugeordnet sind..default_value
definiertFür Eingaben können Benutzer einen primitiven Typ für den Wert ausdrücken.
Die .scan<Shape, T>
-Methode versucht, den eingehenden std::string
nach dem Shape
Konvertierungsspezifizierer in T
zu konvertieren. Bei Fehlern wird eine std::invalid_argument
oder std::range_error
Ausnahme ausgelöst.
program.add_argument( " -x " )
.scan< ' d ' , int >();
program.add_argument( " scale " )
.scan< ' g ' , double >();
Shape
gibt an, wie die Eingabe „aussieht“, und das Typvorlagenargument gibt den Rückgabewert der vordefinierten Aktion an. Akzeptable Typen sind Gleitkomma (dh Float, Double, Long Double) und Integral (dh Signed Char, Short, Int, Long, Long Long).
Die Grammatik folgt std::from_chars
, dupliziert sie jedoch nicht genau. Beispielsweise können Hexadezimalzahlen mit 0x
oder 0X
beginnen und Zahlen mit einer führenden Null können als Oktalwerte behandelt werden.
Form | Interpretation |
---|---|
'a' oder 'A' | Hexadezimaler Gleitkomma |
'e' oder 'E' | wissenschaftliche Notation (Gleitkomma) |
'f' oder 'F' | feste Notation (Gleitkomma) |
'g' oder 'G' | allgemeine Form (entweder fest oder wissenschaftlich) |
'D' | dezimal |
'ich' | std::from_chars Grammatik mit Basis == 10 |
'O' | Oktal (ohne Vorzeichen) |
'du' | Dezimalzahl (ohne Vorzeichen) |
'x' oder 'X' | hexadezimal (ohne Vorzeichen) |
argparse
stellt vordefinierte Argumente und Aktionen für -h
/ --help
und -v
/ --version
bereit. Standardmäßig beenden diese Aktionen das Programm, nachdem eine Hilfe- bzw. Versionsmeldung angezeigt wird. Dieser Exit ruft keine Destruktoren auf und überspringt die Bereinigung der belegten Ressourcen.
Diese Standardargumente können während ArgumentParser
Erstellung deaktiviert werden, sodass Sie diese Argumente auf Ihre eigene Weise verarbeiten können. (Beachten Sie, dass bei der Auswahl der Standardargumente ein Programmname und eine Version angegeben werden müssen.)
argparse::ArgumentParser program ( " test " , " 1.0 " , default_arguments::none);
program.add_argument( " -h " , " --help " )
.action([=]( const std::string& s) {
std::cout << help (). str ();
})
.default_value( false )
.help( " shows help message " )
.implicit_value( true )
.nargs( 0 );
Der obige Codeausschnitt gibt eine Hilfemeldung aus und wird weiter ausgeführt. Es unterstützt kein --version
Argument.
Der Standardwert ist default_arguments::all
für eingeschlossene Argumente. Mit default_arguments::none
werden keine Standardargumente hinzugefügt. default_arguments::help
und default_arguments::version
fügen einzeln --help
und --version
hinzu.
Die Standardargumente können verwendet werden, während der Standardexit mit diesen Argumenten deaktiviert wird. Dieses vierte Argument für ArgumentParser
( exit_on_default_arguments
) ist ein Bool-Flag mit einem standardmäßigen wahren Wert. Der folgende Aufruf behält --help
und --version
bei, wird jedoch nicht beendet, wenn diese Argumente verwendet werden.
argparse::ArgumentParser program ( " test " , " 1.0 " , default_arguments::all, false )
argparse
unterstützt das Sammeln „verbleibender“ Argumente am Ende des Befehls, z. B. zur Verwendung in einem Compiler:
foo@bar:/home/dev/ $ compiler file1 file2 file3
Um dies zu aktivieren, erstellen Sie einfach ein Argument und markieren Sie es als remaining
. Alle übrigen an argparse übergebenen Argumente werden hier gesammelt.
argparse::ArgumentParser program ( " compiler " );
program.add_argument( " files " )
.remaining();
try {
program. parse_args (argc, argv);
}
catch ( const std:: exception & err) {
std::cerr << err. what () << std::endl;
std::cerr << program;
std::exit ( 1 );
}
try {
auto files = program. get <std::vector<std::string>>( " files " );
std::cout << files. size () << " files provided " << std::endl;
for ( auto & file : files)
std::cout << file << std::endl;
} catch (std::logic_error& e) {
std::cout << " No files provided " << std::endl;
}
Wenn keine Argumente angegeben werden:
foo@bar:/home/dev/ $ ./compiler
No files provided
und wenn mehrere Argumente angegeben werden:
foo@bar:/home/dev/ $ ./compiler foo.txt bar.txt baz.txt
3 files provided
foo.txt
bar.txt
baz.txt
Der Prozess des Sammelns verbleibender Argumente funktioniert auch gut mit optionalen Argumenten: