boost::program_options (Befehlszeilen-Parser) Alternative, die Argumente der Reihe nach verarbeiten kann

Ich habe die folgende Frage auf SO gepostet, aber ich denke, ich boost::program_optionskann mir hier nicht helfen:

Ich habe Optionen --foo(Kurzform -f) und --bardie einer besonderen Behandlung bedürfen, sie sind wiederholbar und die Reihenfolge sollte eine Rolle spielen. Also für folgendes:

program --foo 1 --z -f 2 --bar 3 --x --foo 4

Ich möchte eine Key-Value-Map erstellen, die ich erstellen kann [("foo", 1), ("foo", 2), ("bar", 3), ("foo", 4)].

Bitte beachten Sie die Reihenfolge dieses Arrays von Tupeln, sie ist dieselbe wie in der Befehlszeile. Ich habe unwichtige Optionen im Array verworfen, aber sie können trotzdem in der Befehlszeile vorhanden sein.

Es scheint, dass der einzige Weg, wiederholbare Optionen zuzulassen, darin boost::program_optionsbesteht, eine bestimmte Option aufzurufen composing(), aber dann, da jede alle ihre Werte in einem Vektor speichert, verliere ich die Reihenfolge, die ich zum Verschachteln von Optionen benötige.

Also, kann boost::program_optionsdabei helfen?

Quelle: https://stackoverflow.com/questions/36973114/

Ich suche nach einer Bibliothek, mit der ich die geparsten Optionen (wenn möglich mit ihren auf ihre langen oder kurzen Namen normalisierten Namen) in der Reihenfolge durchsuchen kann, die in der Befehlszeile angegeben ist, da eine solche Reihenfolge für mich wichtig ist.

Ich weiß, dass program_optionsIhnen das alles geben kann, was es nicht selbst als vector<string>. Tatsächlich verwende ich dieses hässliche Stück Code , um es in eine Schlüsselwertkarte in einem Projekt einzufügen, an dem ich arbeite, und es sollte nicht schwierig sein, es an das anzupassen, was Sie brauchen, denke ich.
Ah, da ist es: boost::program_options::collect_unrecognized(). Obwohl ich sagen werde, dass Sie wahrscheinlich keine Reihenfolge für Befehlszeilenoptionen annehmen sollten, dh das Problem liegt eher in der Tatsache, dass Sie versuchen, dies IMO zu tun.
@einpoklum nein, ich denke, es gibt kein Problem, dies zu versuchen, der Grund ist, dass ich so etwas tun muss matrix_product_program --matrix="{...}" --matrix="{...}" --matrix="{...}". Irgendein Problem damit, diese Situation mit einer Lösung wie erklärt anzupassen?
Sie wissen, dass die Befehlszeile nicht der Ort ist, an dem Eingabedaten eingegeben werden, oder? Können Sie die Anzahl der Matrizen nicht von der Befehlszeile abrufen und sie dann einfach (z. B. Zeile für Zeile) von der Standardeingabe lesen? Wie auch immer, Sie haben von mir +1 bekommen, da etwas vielseitiger als boost::program_optionsinteressant ist.
@einpoklum auch, danke für diese Hinweise, wahrscheinlich wird es eine große Hilfe sein, ich werde sie überprüfen.
@einpoklum das war nur zur Veranschaulichung, da das Matrixprodukt nicht pendelt. Die Standardeingabe kommt für mich nicht in Frage, da es in meinem Fall in Wahrheit nicht um Matrizen und komplexe Eingabedaten geht, sondern nur um einfache Strings.
@einpoklum Nun, angesichts des Kontexts collect_unrecognizedund des von Ihnen gesendeten Ausschnitts ... Es sieht nicht so gut aus, wie ich erwartet hatte. Sehen Sie, dass ich sogar erwähnt habe, dass Optionsnamen normalisiert wurden (was bedeutet, dass sie erkannt wurden), verbunden mit entsprechenden Werten.
Nun, ich habe dich gewarnt, dass es hässlich ist...

Antworten (2)

Verwenden des neuesten Masters in CLI11 (wird in Version 1.1 sein) (jetzt auch ein offizielles Beispiel):

#include <CLI/CLI.hpp>
#include <iostream>
#include <vector>
#include <tuple>
#include <algorithm>

int main(int argc, char **argv) {
    CLI::App app;

    std::vector<int> foos;
    auto foo = app.add_option("--foo,-f", foos);

    std::vector<int> bars;
    auto bar = app.add_option("--bar", bars);

    app.add_flag("--z,--x"); // Random other flags

    try {
        app.parse(argc, argv);
    } catch(const CLI::ParseError &e) {
        return app.exit(e);
    }

    // I perfer using the back and popping
    std::reverse(std::begin(foos), std::end(foos));
    std::reverse(std::begin(bars), std::end(bars));

    std::vector<std::pair<std::string, int>> keyval;
    for(auto option : app.parse_order()) {
        if(option == foo) {
            keyval.emplace_back("foo", foos.back());
            foos.pop_back();
        }
        if(option == bar) {
            keyval.emplace_back("bar", bars.back());
            bars.pop_back();
        }
    }

    // Prove the vector is correct
    for(auto &pair : keyval) {
        std::cout << pair.first << " : " << pair.second << std::endl;
    }
}

Ausgabe:

./examples/inter_argument_order --foo 1 --z -f 2 --bar 3 --x --foo 4
foo : 1
foo : 2
bar : 3
foo : 4

Verwenden von Poco, das einen Rückruf pro Flag aufruft, in der folgenden Reihenfolge:

#include <iostream>

#include <Poco/Util/Option.h>
#include <Poco/Util/OptionSet.h>
#include <Poco/Util/Application.h>
#include <Poco/Util/HelpFormatter.h>

using Poco::Util::Option;
using Poco::Util::OptionSet;
using Poco::Util::Application;
using Poco::Util::HelpFormatter;
using Poco::Util::OptionCallback;

struct SampleApp : Application {
    void defineOptions(OptionSet &options) {
        Application::defineOptions(options);

        options.addOption(Option("help", "h", "display help information")
                              .required(false)
                              .repeatable(false)
                              .callback(OptionCallback<SampleApp>(
                                  this, &SampleApp::handleHelp)));

        options.addOption(Option("foo", "f", "foo option")
                              .required(false)
                              .repeatable(true)
                              .argument("<foo>")
                              .callback(OptionCallback<SampleApp>(
                                  this, &SampleApp::handleOptions)));

        options.addOption(Option("bar", "b", "bar option")
                              .required(false)
                              .repeatable(false)
                              .argument("<bar>")
                              .callback(OptionCallback<SampleApp>(
                                  this, &SampleApp::handleOptions)));

        options.addOption(Option("z", "", "z option")
                              .required(false)
                              .callback(OptionCallback<SampleApp>(
                                  this, &SampleApp::handleOptions)));

        options.addOption(Option("x", "", "x option")
                              .required(false)
                              .callback(OptionCallback<SampleApp>(
                                  this, &SampleApp::handleOptions)));
    }

    void handleHelp(const std::string &, const std::string &) {
        helpRequested = true;
        displayHelp();
        stopOptionsProcessing();
    }

    void handleOptions(const std::string &name, const std::string &value) {
        std::cout << name << " " << value << std::endl;
    }

    void displayHelp() {
        HelpFormatter helpFormatter(options());
        helpFormatter.setCommand(commandName());
        helpFormatter.setUsage("<options>");
        helpFormatter.setHeader("Foo/Bar options.");
        helpFormatter.format(std::cout);
    }

    bool helpRequested = false;
};

POCO_APP_MAIN(SampleApp)

AUSGANG

❯❯❯ ./sample --help
usage: sample <options>
Foo/Bar options.

-h, --help            display help information
-f<foo>, --foo=<foo>  foo option
-b<bar>, --bar=<bar>  bar option
--z                   z option
--x                   x option
❯❯❯ ./sample --foo 1 --z -f 2 --bar 3 --x --foo 4
foo 1
z 
foo 2
bar 3
x 
foo 4