Come analizzare gli argomenti della riga di comando in C ++?

Possibile duplicato:
Quali sono le librerie di parser dei parametri per C ++?

Qual è il modo migliore di analizzare gli argomenti della riga di comando in C ++ se il programma è specificato per essere eseguito in questo modo:

prog [-abc] [input [output]] 

C’è una libreria in STL per fare questo?


Relazionato:

  • Analizzare gli argomenti della riga di comando in un’applicazione C ++ unicode

Boost.Program_options dovrebbe fare il trucco

I suggerimenti per boost::program_options e GNU getopt sono buoni.

Tuttavia, per le semplici opzioni della riga di comando tendo a usare std :: find

Ad esempio, per leggere il nome di un file dopo un argomento della riga di comando -f . Puoi anche solo rilevare se è stata passata un’opzione a parola singola come -h come aiuto.

 #include  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; } 

Su cosa fare attenzione con questo approccio, devi usare std :: string come valore per std :: find altrimenti il ​​controllo di uguaglianza viene eseguito sui valori del puntatore.


Spero che sia corretto modificare questa risposta aggiungendone una nuova, poiché si basa sulla risposta originale. Ho riscritto le funzioni leggermente e le ho incapsulate in una class, quindi ecco il codice. Ho pensato che potrebbe essere pratico usarlo anche in questo modo:

 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::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  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; } 

Posso suggerire la libreria Parser della riga di comando Templatized C ++ (sono disponibili alcune forchette su GitHub ), l’API è molto semplice e (citata dal sito):

la libreria è implementata interamente nei file di intestazione, rendendola facile da usare e distribuire con altri software. È concesso in licenza con la licenza MIT per la distribuzione senza preoccupazioni.

Questo è un esempio del manuale, colorato qui per semplicità:

 #include  #include  #include  #include  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 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; } } 

È ansible utilizzare GNU GetOpt (LGPL) o una delle varie porte C ++, come getoptpp (GPL).

Un semplice esempio che usa GetOpt di ciò che vuoi ( prog [-ab] input ) è il seguente:

 // C Libraries: #include  #include  #include  // 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; } 

Un’altra alternativa è il parser dell’opzione C ++ Lean Mean:

http://optionparser.sourceforge.net

È una libreria di sola intestazione (solo un singolo file di intestazione, infatti) e, a differenza di tutti gli altri suggerimenti, è anche indipendente, cioè non ha alcuna dipendenza. In particolare non c’è dipendenza dal STL. Non usa nemmeno le eccezioni o qualsiasi altra cosa che richiede il supporto della libreria. Ciò significa che può essere collegato a una semplice C o ad altre lingue senza introdurre librerie “straniere”.

Come boost :: program_options, la sua API offre un comodo accesso diretto alle opzioni, ovvero puoi scrivere un codice come questo

if (opzioni [HELP]) …;

e

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

A differenza di boost :: program_options, tuttavia, questo è semplicemente utilizzando un array indicizzato con un enum (fornito dall’utente). Questo offre la comodità di un contenitore associativo senza il peso.

È ben documentato e ha una licenza aziendale (MIT).

TLMC ++ OP include un buon formattatore per i messaggi di utilizzo in grado di eseguire il line-wrapping e l’allineamento delle colonne, utile se stai localizzando il tuo programma, perché garantisce che l’output risulti buono anche in lingue con messaggi più lunghi. Inoltre, ti risparmia la seccatura di formattare manualmente il tuo utilizzo per 80 colonne.

 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); } } 

AnyOption è una class C ++ per l’analisi semplice di opzioni complesse della riga di comando. Analizza anche le opzioni da un file rsource nel formato della coppia di valori dell’opzione.

AnyOption implementa le tradizionali opzioni di carattere di stile POSIX (-n) e le più recenti opzioni di stile GNU (–name). Oppure puoi usare una versione più semplice dell’opzione lunga (-name) chiedendo di ignorare le opzioni di stile POSIX.

Consiglierei boost :: program_options se puoi usare la lib di Boost.

Non c’è nulla di specifico in STL né nelle normali librerie di runtime C ++ / C.

Prova la libreria CLPP. È una libreria semplice e flessibile per l’analisi dei parametri della riga di comando. Solo testata e multipiattaforma. Utilizza solo librerie ISO C ++ e Boost C ++. IMHO è più semplice di Boost.Program_options.

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

26 ottobre 2010 – nuova versione 2.0rc. Molti errori risolti, refactoring completo del codice sorgente, documentazione, esempi e commenti sono stati corretti.

Una risposta piuttosto tardiva, ma ho utilizzato GetPot per alcuni progetti: http://getpot.sourceforge.net/

Caratteristica principale: tutto è in un singolo file di intestazione, senza problemi di build. Basta salvarlo da qualche parte sul tuo computer e “#include” nel tuo file contenente main()

Non è stato aggiornato di recente, ma è ben documentato e funziona bene. Puoi provare.