web-dev-qa-db-fra.com

Comment analyser les arguments de ligne de commande en C ++?

Duplicate possible:
Quelles bibliothèques d’analyseurs de paramètres existe-t-il pour C++?

Quel est le meilleur moyen d’analyser les arguments de ligne de commande en C++ si le programme doit être exécuté de la manière suivante:

prog [-abc] [input [output]]

Y a-t-il une bibliothèque dans STL pour le faire?


Apparenté, relié, connexe:

179
Verhogen

Boost.Program_options devrait faire l'affaire

83
ultraman

Les suggestions pour boost::program_options et GNU getopt sont bonnes.

Cependant, pour les options simples en ligne de commande, j’ai tendance à utiliser std :: find

Par exemple, pour lire le nom d'un fichier après un argument de ligne de commande -f. Vous pouvez également simplement détecter si une option Word unique a été transmise comme -h pour obtenir de l'aide.

#include <algorithm>

char* getCmdOption(char ** begin, char ** end, const std::string & option)
{
    char ** itr = std::find(begin, end, option);
    if (itr != end && ++itr != end)
    {
        return *itr;
    }
    return 0;
}

bool cmdOptionExists(char** begin, char** end, const std::string& option)
{
    return std::find(begin, end, option) != end;
}

int main(int argc, char * argv[])
{
    if(cmdOptionExists(argv, argv+argc, "-h"))
    {
        // Do stuff
    }

    char * filename = getCmdOption(argv, argv + argc, "-f");

    if (filename)
    {
        // Do interesting things
        // ...
    }

    return 0;
}

Sur la chose à rechercher avec cette approche, vous devez utiliser std :: strings comme valeur pour std :: find, sinon le contrôle d'égalité est effectué sur les valeurs du pointeur.


J'espère que vous pourrez modifier cette réponse au lieu d'en ajouter une nouvelle, car celle-ci est basée sur la réponse d'origine. J'ai légèrement réécrit les fonctions et les ai encapsulées dans une classe. Voici donc le code. J'ai pensé qu'il serait peut-être pratique de l'utiliser aussi:

class InputParser{
    public:
        InputParser (int &argc, char **argv){
            for (int i=1; i < argc; ++i)
                this->tokens.Push_back(std::string(argv[i]));
        }
        /// @author iain
        const std::string& getCmdOption(const std::string &option) const{
            std::vector<std::string>::const_iterator itr;
            itr =  std::find(this->tokens.begin(), this->tokens.end(), option);
            if (itr != this->tokens.end() && ++itr != this->tokens.end()){
                return *itr;
            }
            static const std::string empty_string("");
            return empty_string;
        }
        /// @author iain
        bool cmdOptionExists(const std::string &option) const{
            return std::find(this->tokens.begin(), this->tokens.end(), option)
                   != this->tokens.end();
        }
    private:
        std::vector <std::string> tokens;
};

int main(int argc, char **argv){
    InputParser input(argc, argv);
    if(input.cmdOptionExists("-h")){
        // Do stuff
    }
    const std::string &filename = input.getCmdOption("-f");
    if (!filename.empty()){
        // Do interesting things ...
    }
    return 0;
}
229
iain

Je peux suggérer bibliothèque d’analyseurs en ligne de commande C++ modélisée (certains forks sur GitHub sont disponibles), l’API est très simple et (cité sur le site):

la bibliothèque est entièrement implémentée dans des fichiers d’en-tête, ce qui facilite son utilisation et sa distribution avec d’autres logiciels. Il est licencié sous la licence MIT pour une distribution sans souci.

Voici un exemple tiré du manuel, coloré ici pour plus de simplicité:

#include <string>
#include <iostream>
#include <algorithm>
#include <tclap/CmdLine.h>

int main(int argc, char** argv)
{

    // Wrap everything in a try block.  Do this every time,
    // because exceptions will be thrown for problems.
    try {

    // Define the command line object, and insert a message
    // that describes the program. The "Command description message"
    // is printed last in the help text. The second argument is the
    // delimiter (usually space) and the last one is the version number.
    // The CmdLine object parses the argv array based on the Arg objects
    // that it contains.
    TCLAP::CmdLine cmd("Command description message", ' ', "0.9");

    // Define a value argument and add it to the command line.
    // A value arg defines a flag and a type of value that it expects,
    // such as "-n Bishop".
    TCLAP::ValueArg<std::string> nameArg("n","name","Name to print",true,"homer","string");

    // Add the argument nameArg to the CmdLine object. The CmdLine object
    // uses this Arg to parse the command line.
    cmd.add( nameArg );

    // Define a switch and add it to the command line.
    // A switch arg is a boolean argument and only defines a flag that
    // indicates true or false.  In this example the SwitchArg adds itself
    // to the CmdLine object as part of the constructor.  This eliminates
    // the need to call the cmd.add() method.  All args have support in
    // their constructors to add themselves directly to the CmdLine object.
    // It doesn't matter which idiom you choose, they accomplish the same thing.
    TCLAP::SwitchArg reverseSwitch("r","reverse","Print name backwards", cmd, false);

    // Parse the argv array.
    cmd.parse( argc, argv );

    // Get the value parsed by each arg.
    std::string name = nameArg.getValue();
    bool reverseName = reverseSwitch.getValue();

    // Do what you intend.
    if ( reverseName )
    {
            std::reverse(name.begin(),name.end());
            std::cout << "My name (spelled backwards) is: " << name << std::endl;
    }
    else
            std::cout << "My name is: " << name << std::endl;


    } catch (TCLAP::ArgException &e)  // catch any exceptions
    { std::cerr << "error: " << e.error() << " for arg " << e.argId() << std::endl; }
}
58
naufraghi

Vous pouvez utiliser GNU GetOpt (LGPL) ou l'un des différents ports C++, tels que getoptpp (GPL).

Voici un exemple simple utilisant GetOpt de ce que vous voulez ( prog [-ab] input ):

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

// Namespaces:
using namespace std;

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

    // Retrieve the (non-option) argument:
    if ( (argc <= 1) || (argv[argc-1] == NULL) || (argv[argc-1][0] == '-') ) {  // there is NO input...
        cerr << "No argument provided!" << endl;
        //return 1;
    }
    else {  // there is an input...
        input = argv[argc-1];
    }

    // Debug:
    cout << "input = " << input << endl;

    // 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;
}
32
Matthew Flaschen

Une autre alternative est l’analyseur d’options Lean Mean C++:

http://optionparser.sourceforge.net

C’est une bibliothèque d’en-tête uniquement (en fait, un seul fichier d’en-tête) et, contrairement à toutes les autres suggestions, elle est également autonome, c’est-à-dire qu’elle n’a aucune dépendance. En particulier, il n'y a pas de dépendance à la STL. Il n'utilise même pas d'exceptions ni quoi que ce soit qui nécessite le support de la bibliothèque. Cela signifie qu’il peut être lié au C ou à d’autres langages sans introduire de bibliothèques "étrangères".

Comme boost :: program_options, son API offre un accès direct pratique aux options, c’est-à-dire que vous pouvez écrire du code comme celui-ci.

if (options [HELP]) ...;

et

int verbosity = options [VERBOSE] .count ();

Contrairement à boost :: program_options, il utilise simplement un tableau indexé avec un enum (fourni par l'utilisateur). Cela offre la commodité d'un conteneur associatif sans le poids.

Il est bien documenté et possède une licence adaptée aux entreprises (MIT).

TLMC++ OP inclut un formateur Nice pour les messages d’utilisation pouvant effectuer le retour à la ligne et l’alignement des colonnes, ce qui est utile si vous localisez votre programme, car il garantit que la sortie aura une belle apparence même dans les langues où les messages sont plus longs. Cela vous évite également la mise en forme manuelle de votre utilisation pour 80 colonnes.

21
MSB
for (int i = 1; i < argc; i++) {

    if (strcmp(argv[i],"-i")==0) {
        filename = argv[i+1];
        printf("filename: %s",filename);
    } else if (strcmp(argv[i],"-c")==0) {
        convergence = atoi(argv[i + 1]);
        printf("\nconvergence: %d",convergence);
    } else if (strcmp(argv[i],"-a")==0) {
        accuracy = atoi(argv[i + 1]);
        printf("\naccuracy:%d",accuracy);
    } else if (strcmp(argv[i],"-t")==0) {
        targetBitRate = atof(argv[i + 1]);
        printf("\ntargetBitRate:%f",targetBitRate);
    } else if (strcmp(argv[i],"-f")==0) {
        frameRate = atoi(argv[i + 1]);
        printf("\nframeRate:%d",frameRate);
    }

}
11
Oliver Nina

AnyOption est une classe C++ facilitant l'analyse syntaxique d'options de ligne de commande complexes. Il analyse également les options d’un fichier rsource au format paire d’options.

AnyOption implémente les options de caractère de style POSIX traditionnelles (-n), ainsi que les nouvelles options de style GNU (--name). Ou vous pouvez utiliser une version d'option longue plus simple (-name) en demandant d'ignorer les options de style POSIX.

5
Jay

Je recommanderais boost :: program_options si vous pouvez utiliser la librairie Boost.

Il n'y a rien de spécifique dans STL ni dans les bibliothèques d'exécution régulières C++/C.

3
Macke

Essayez la bibliothèque CLPP. C'est une bibliothèque simple et flexible pour l'analyse des paramètres de ligne de commande. En-tête uniquement et multiplate-forme. Utilise uniquement les bibliothèques ISO C++ et Boost C++. À mon humble avis, il est plus facile que Boost.Program_options.

Bibliothèque: http://sourceforge.net/projects/clp-parser

26 octobre 2010 - nouvelle version 2.0rc. Beaucoup de bugs corrigés, refactoring complet du code source, documentation, exemples et commentaires ont été corrigés.

2

Réponse assez tardive, mais j'ai utilisé GetPot pour certains projets: http://getpot.sourceforge.net/

Caractéristique principale: tout est dans un seul fichier d'en-tête, pas de soucis de construction. Enregistrez-le simplement quelque part sur votre ordinateur et "#include" dans votre dossier en conservant main()

N'a pas été mis à jour récemment, mais joliment documenté et fonctionne bien. Vous pouvez essayer.

2
kebs