Welche Parameter-Parser-Bibliotheken gibt es für C ++? [geschlossen]

76

Ich möchte Parameter auf folgende Weise an mein C ++ - Programm übergeben:

./myprog --setting=value

Gibt es Bibliotheken, die mir dabei helfen?

Siehe auch Helfer zum Parsen von Argumenten für C und Unix

Jim
quelle
Kürzlich schrieb dies für modernes c ++: github.com/juzzlin/Argengine
juzzlin

Antworten:

45

Boost.Program_options

Igor Semenov
quelle
13
Dies scheint die naheliegendste Option für C ++ zu sein, aber die Dokumentation ist nicht vollständig genug. Versuchen Sie dort herauszufinden, wie Optionen in einer Datei gespeichert und abgerufen werden können. Dies ist eine wesentliche Funktion. Ich mag es nicht, wie der Code aussieht, der ihn verwendet, insbesondere den Wortlaut, options.add_options()(option1)(option2)...den ich als Missbrauch der C ++ - Grammatik betrachte.
Gatopeich
8
Das Kompilieren von Code mit Boost.Program_options schien nicht einfach zu sein und erforderte Verknüpfungsoptionen usw. über die Aufnahme der Header-Datei hinaus.
Richard
2
Sie können so ziemlich das Gleiche für viel weniger bekommen. Wenn Sie Dinge wie möchten --long-option, ist es ziemlich einfach, sich selbst zu tun.
Luis Machuca
In einem Extremfall für wirklich einfache Programme oder wenn Sie direkt mit dem Array argv [] arbeiten. In einer anderen Situation können Sie für eine vollständige Flexibilität Ihrer Argumente direkt mit dem Array argv arbeiten (Sie können prog -1 firstinput -2 second input -obj {Konstruktorargumente ..} ausführen). Verwenden Sie andernfalls Boost, Tclap oder viele andere.
Kemin Zhou
boost::program_optionsist hoffnungslos überarbeitet, schwer zu bedienen und unterdokumentiert. Eine der wenigen Boost-Bibliotheken, die von einer vollständigen Neugestaltung und Neufassung stark profitieren würden. Verwenden Sie es nicht, wenn Sie es vermeiden können.
Laryx Decidua
26

GNU GetOpt .

Ein einfaches Beispiel mit GetOpt:

// C/C++ Libraries:
#include <string>
#include <iostream>
#include <unistd.h>

// Namespaces:
using namespace std;

int main(int argc, char** argv) {
    int opt;
    bool flagA = false;
    bool flagB = false;

    // Shut GetOpt error messages down (return '?'): 
    opterr = 0;

    // Retrieve the options:
    while ( (opt = getopt(argc, argv, "ab")) != -1 ) {  // for each option...
        switch ( opt ) {
            case 'a':
                    flagA = true;
                break;
            case 'b':
                    flagB = true;
                break;
            case '?':  // unknown option...
                    cerr << "Unknown option: '" << char(optopt) << "'!" << endl;
                break;
        }
    }

    // Debug:
    cout << "flagA = " << flagA << endl;
    cout << "flagB = " << flagB << endl;

    return 0;
}

Sie können optarg auch verwenden, wenn Sie Optionen haben, die Argumente akzeptieren.

Marcin Gil
quelle
14
Ughh. Ich verstehe die Verwendung dieser Bibliothek in C-Code, aber IMO, dies ist viel zu niedrig, um in einer C ++ - Anwendung, die ich jemals geschrieben habe, akzeptabel zu sein. Finden Sie eine bessere Bibliothek, wenn Sie kein reines C benötigen.
Thomas Eding
1
Es gibt auch ein GNU-Beispiel für getopt mit einem Wert, z. B. myexe -c myvalue. Sie können versuchen, nach "Beispiel für das Parsen von Argumenten mit getopt" zu suchen
edW
Hier ist ein Beispiel, das von der GNU selbst bereitgestellt wurde ^^
finnmglas
19

Ich finde es einfacher, ezOptionParser zu verwenden . Es ist auch eine einzelne Header-Datei, hängt von nichts anderem als STL ab, funktioniert für Windows und Linux (sehr wahrscheinlich auch für andere Plattformen), hat dank der Beispiele keine Lernkurve und verfügt über Funktionen, die andere Bibliotheken nicht haben (wie den Import / Export von Dateien) mit Kommentaren, beliebigen Optionsnamen mit Trennzeichen, Formatierung der automatischen Verwendung usw.) und ist LGPL-lizenziert.

Remik Ziemlinski
quelle
1
Ab Version 0.1.3 lautet die Lizenz jetzt MIT. Ich probiere dies an einem neuen Projekt anstelle von TCLAP aus und bisher sieht es sehr vielversprechend aus. Die Dateikonfigurationsoption ist ganz nett.
Sean
6
Ich habe gerade exOptionParser ausprobiert, aber es gibt so viele Probleme. Zunächst erhalte ich 58 Warnungen bezüglich der vorzeichenlosen Int-Int-Konvertierung. Es wird auch versucht, Listeniteratoren (die so nicht verwendet werden können) zu erhöhen, und es stürzt ab. Die Schnittstelle ist auch so schrecklich. Es werden überall Referenzen verwendet, anstatt nur die gewünschten Daten zurückzugeben. Es sieht aus wie eine C-Bibliothek, obwohl sie auf der C ++ STL basiert.
Andrew Larsson
Hinweis; Die Erkennung unbekannter Argumente funktioniert nicht. Außerdem gibt der Header Kompilierungsfehler aus, wenn er nicht vor anderen Headern platziert wird. Ich werde nach einem anderen Parser suchen.
Totte Karlsson
19

TCLAPist ein wirklich schönes, leichtes Design und einfach zu bedienen: http://tclap.sourceforge.net/

cheshirekow
quelle
4
Ich habe getopt, googles gflags, program_options von Boost verwendet und tclap ist fantastisch . Ich kann nicht genug gute Dinge über tclap sagen, besonders angesichts der verfügbaren Alternativen. Das Ausmaß der Griffe, die ich habe, ist, dass die Formatierung der Hilfe "anders" ist als das, was mein Auge gewohnt ist.
Sean
16

Und es gibt eine Google-Bibliothek .

Die Befehlszeilenanalyse ist wirklich "gelöst". Wähle einfach einen aus.

Max Lybbert
quelle
(Vielen Dank an @QPaysTaxes, dass Sie bemerkt haben, dass der Link unterbrochen wurde. Ich weiß nicht, warum Ihre Bearbeitung abgelehnt wurde, aber Sie hatten definitiv Recht).
Max Lybbert
5
Ich kann mir keine weniger hilfreiche Antwort auf eine Frage vorstellen. 'Es ist gelöst. Wähle eins.' Entschuldigung, aber "duh". Nachdem ich ungefähr 15 Minuten über dieses Problem nachgedacht habe, habe ich mir ungefähr 30 verschiedene Szenarien ausgedacht, wie man es angehen könnte. Ich vermute, dass die "richtige" Antwort eher der Erklärung entspricht, wie ein bestimmter Satz von Bedenken zu einem bestimmten Satz von Code-Implementierungen führen würde. Aber hey, danke, dass du angerufen hast.
MarkWayne
10

Ich denke, dass GNU GetOpt nicht zu unmittelbar zu verwenden ist.

Qt und Boost könnten eine Lösung sein, aber Sie müssen viel Code herunterladen und kompilieren.

Also habe ich selbst einen Parser implementiert, der eine std :: map <std :: string, std :: string> von Parametern erzeugt.

Zum Beispiel:

 ./myProgram -v -p 1234

Karte wird sein:

 ["-v"][""]
 ["-p"]["1234"]

Verwendung ist:

int main(int argc, char *argv[]) {
    MainOptions mo(argc, argv);
    MainOptions::Option* opt = mo.getParamFromKey("-p");
    const string type = opt ? (*opt).second : "";
    cout << type << endl; /* Prints 1234 */
    /* Your check code */
}

MainOptions.h

#ifndef MAINOPTIONS_H_
#define MAINOPTIONS_H_

#include <map>
#include <string>

class MainOptions {
public:
    typedef std::pair<std::string, std::string> Option;
    MainOptions(int argc, char *argv[]);
    virtual ~MainOptions();
    std::string getAppName() const;
    bool hasKey(const std::string&) const;
    Option* getParamFromKey(const std::string&) const;
    void printOptions() const;
private:
    typedef std::map<std::string, std::string> Options;
    void parse();
    const char* const *begin() const;
    const char* const *end() const;
    const char* const *last() const;
    Options options_;
    int argc_;
    char** argv_;
    std::string appName_;
};

MainOptions.cpp

#include "MainOptions.h"

#include <iostream>

using namespace std;

MainOptions::MainOptions(int argc, char* argv[]) :
        argc_(argc),
        argv_(argv) {
    appName_ = argv_[0];
    this->parse();
}

MainOptions::~MainOptions() {
}

std::string MainOptions::getAppName() const {
    return appName_;
}

void MainOptions::parse() {
    typedef pair<string, string> Option;
    Option* option = new pair<string, string>();
    for (const char* const * i = this->begin() + 1; i != this->end(); i++) {
        const string p = *i;
        if (option->first == "" && p[0] == '-') {
            option->first = p;
            if (i == this->last()) {
                options_.insert(Option(option->first, option->second));
            }
            continue;
        } else if (option->first != "" && p[0] == '-') {
            option->second = "null"; /* or leave empty? */
            options_.insert(Option(option->first, option->second));
            option->first = p;
            option->second = "";
            if (i == this->last()) {
                options_.insert(Option(option->first, option->second));
            }
            continue;
        } else if (option->first != "") {
            option->second = p;
            options_.insert(Option(option->first, option->second));
            option->first = "";
            option->second = "";
            continue;
        }
    }
}

void MainOptions::printOptions() const {
    std::map<std::string, std::string>::const_iterator m = options_.begin();
    int i = 0;
    if (options_.empty()) {
        cout << "No parameters\n";
    }
    for (; m != options_.end(); m++, ++i) {
        cout << "Parameter [" << i << "] [" << (*m).first << " " << (*m).second
                << "]\n";
    }
}

const char* const *MainOptions::begin() const {
    return argv_;
}

const char* const *MainOptions::end() const {
    return argv_ + argc_;
}

const char* const *MainOptions::last() const {
    return argv_ + argc_ - 1;
}

bool MainOptions::hasKey(const std::string& key) const {
    return options_.find(key) != options_.end();
}

MainOptions::Option* MainOptions::getParamFromKey(
        const std::string& key) const {
    const Options::const_iterator i = options_.find(key);
    MainOptions::Option* o = 0;
    if (i != options_.end()) {
        o = new MainOptions::Option((*i).first, (*i).second);
    }
    return o;
}
Luca Davanzo
quelle
2
Was meinst du mit "... ist nicht zu unmittelbar zu verwenden" ? Können Sie das näher erläutern?
Peter Mortensen
8

Es gibt diese Tools in der GNU C-Bibliothek, die GetOpt enthält .

Wenn Sie Qt und wie die getopt Schnittstelle verwenden, froglogic hat eine schöne Oberfläche veröffentlicht hier .

Dusty Campbell
quelle
7

Wenn ich mein eigenes Horn betätigen darf, möchte ich auch vorschlagen, einen Blick auf eine von mir geschriebene Option zum Parsen von Bibliotheken zu werfen: dropt .

  • Es ist eine C-Bibliothek (mit einem C ++ - Wrapper, falls gewünscht).
  • Es ist leicht.
  • Es ist erweiterbar (benutzerdefinierte Argumenttypen können einfach hinzugefügt werden und sind den integrierten Argumenttypen gleichgestellt).
  • Es sollte sehr portabel sein (es ist in Standard C geschrieben) und keine Abhängigkeiten aufweisen (außer der C-Standardbibliothek).
  • Es hat eine sehr uneingeschränkte Lizenz (zlib / libpng).

Eine Funktion, die viele andere nicht bieten, ist die Möglichkeit, frühere Optionen zu überschreiben. Wenn Sie beispielsweise einen Shell-Alias ​​haben:

alias bar="foo --flag1 --flag2 --flag3"

und Sie möchten verwenden, baraber mit --flag1deaktiviert, ermöglicht es Ihnen, Folgendes zu tun:

bar --flag1=0
Jamesdlin
quelle
1
Das sieht ziemlich ordentlich aus. Ich bin froh, dass ich nach unten gescrollt habe. Es gibt einfach nichts sehr Gutes für C, außer dies!
Asherah
Klingt gut, scheint aber etwas zu groß. Außerdem suche ich nur nach einer Möglichkeit, Scanf-Formatspezifizierer aus einem Argument zu analysieren. Ich habe bereits meinen eigenen (wenn auch grundlegenderen) Parser geschrieben.
MarcusJ
1
@MarcusJ Es scheint ein wenig seltsam, dass Sie sagen, dass dies zu groß ist (es ist viel kleiner als die meisten anderen Befehlszeilenoptions-Parser), aber dass Sie möchten, dass es Printf / Scanf-Formatspezifizierer analysiert (was nicht die Befehlszeile ist Option Parser tun normalerweise) ...
Jamesdlin
Ja, ich weiß, dass ich einige spezifische Anforderungen dafür habe. Ich werde einfach meinen Optionsparser neu schreiben, aber ich habe mir Ihren Code angesehen und die Idee, eine Struktur zu übergeben, die die verschiedenen Optionen enthält, ist wirklich interessant (Bisher ist meine nur fest codiert). Es ist für sich genommen nicht zu groß, es ist nur so, dass ich ein einzelnes .c / .h-Projekt habe und Ihr Code die Menge an Code verdoppeln würde, die ich bereits habe, also ist es zu groß für mein spezifisches Projekt.
MarcusJ
5

Qt 5.2 wird mit einer Befehlszeilen-Parser-API geliefert .

Kleines Beispiel:

#include <QCoreApplication>
#include <QCommandLineParser>
#include <QDebug>

int main(int argc, char **argv)
{
  QCoreApplication app(argc, argv);
  app.setApplicationName("ToolX");
  app.setApplicationVersion("1.2");

  QCommandLineParser parser;
  parser.setApplicationDescription("Tool for doing X.");
  parser.addHelpOption();
  parser.addVersionOption();
  parser.addPositionalArgument("infile",
      QCoreApplication::translate("main", "Input file."));

  QCommandLineOption verbose_opt("+",
      QCoreApplication::translate("main", "be verbose"));
  parser.addOption(verbose_opt);

  QCommandLineOption out_opt(QStringList() << "o" << "output",
      QCoreApplication::translate("main", "Output file."),
      QCoreApplication::translate("main", "filename"), // value name
      QCoreApplication::translate("main", "out")   // default value
      );
  parser.addOption(out_opt);

  // exits on error
  parser.process(app);

  const QStringList args = parser.positionalArguments();

  qDebug() << "Input files: " << args
    << ", verbose: " << parser.isSet(verbose_opt)
    << ", output: " << parser.value(out_opt)
    << '\n';
  return 0;
}

Beispielausgabe

Der automatisch generierte Hilfebildschirm:

$ ./qtopt -h
Verwendung: ./qtopt [Optionen] infile
Tool für X.

Optionen:
  -h, --help Zeigt diese Hilfe an.
  -v, --version Zeigt Versionsinformationen an.
  - + wortreich sein
  -o, --output Ausgabedatei.

Argumente:
  infile Eingabedatei.

Automatisch generierte Versionsausgabe:

$ ./qtopt -v
ToolX 1.2

Einige echte Anrufe:

$ ./qtopt b1 - + -o tmp blah.foo
Eingabedateien: ("b1", "blah.foo"), ausführlich: true, Ausgabe: "tmp"
$ ./qtopt          
Eingabedateien: (), ausführlich: false, Ausgabe: "out"

Ein Analysefehler:

$ ./qtopt --hlp
Unbekannte Option 'hlp'.
$ echo $?
1

Fazit

Wenn Ihr Programm bereits die Qt-Bibliotheken (> = 5.2) verwendet, ist die Befehlszeilen-Parsing-API praktisch genug, um die Aufgabe zu erledigen.

Beachten Sie, dass integrierte Qt-Optionen von verwendet werden, QApplicationbevor der Optionsparser ausgeführt wird.

maxschlepzig
quelle
3

argstreamist ziemlich ähnlich zu boost.program_option: Es erlaubt das Binden von Variablen an Optionen usw. Es behandelt jedoch keine Optionen, die in einer Konfigurationsdatei gespeichert sind.

Luc Hermitte
quelle
3

Versuchen Sie es mit der CLPP-Bibliothek. Es ist eine einfache und flexible Bibliothek zum Parsen von Befehlszeilenparametern. Nur Header und plattformübergreifend. Verwendet nur ISO C ++ - und Boost C ++ - Bibliotheken. IMHO ist es einfacher als Boost.Program_options.

Bibliothek: http://sourceforge.net/projects/clp-parser/

26. Oktober 2010 - neue Version 2.0rc. Viele Fehler behoben, das vollständige Refactoring des Quellcodes, der Dokumentation, Beispiele und Kommentare wurde korrigiert.

Denis Shevchenko
quelle
1

Sie könnten meinen kleinen Options- Header (166 loc so leicht hackbar) options.hpp ausprobieren . Es ist eine einzelne Header-Implementierung und sollte das tun, was Sie verlangen. Außerdem wird die Hilfeseite automatisch gedruckt.

Brenner
quelle