web-dev-qa-db-ja.com

C ++でコマンドライン引数を解析する方法は?

可能性のある複製:
C++にはどのパラメーターパーサーライブラリがありますか?

プログラムが次のように実行されるように指定されている場合、C++でコマンドライン引数を解析する最良の方法は何ですか。

prog [-abc] [input [output]]

これを行うためのライブラリがSTLにありますか?


関連:

175
Verhogen

Boost.Program_options トリックを行う必要があります

82
ultraman

boost::program_optionsおよびGNU getoptの提案は良いものです。

ただし、単純なコマンドラインオプションの場合は、std :: findを使用する傾向があります。

たとえば、-fコマンドライン引数の後にファイルの名前を読み取る場合。また、ヘルプのために-hのような単一のWordオプションが渡されたかどうかを検出することもできます。

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

このアプローチで注目すべきことは、std :: findsの値としてstd :: stringsを使用する必要があることです。そうでない場合は、ポインター値に対して等値チェックが実行されます。


元の回答に基づいているため、新しい応答を追加する代わりにこの応答を編集しても問題ないことを願っています。関数を少し書き直してクラスにカプセル化したので、ここにコードを示します。私もそれをそのように使用することが実用的であると思った:

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;
}
221
iain

Tempplatized C++ Command Line Parser Library (一部の GitHubのフォーク が利用可能です)、APIは非常に簡単で(サイトから引用)を提案できます:

ライブラリはヘッダーファイルに完全に実装されているため、他のソフトウェアとの使用や配布が簡単です。安心して配布できるよう、MITライセンスの下でライセンスされています。

これは、簡単にするためにここに色を付けたマニュアルの例です。

#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; }
}
57
naufraghi

GNU GetOpt (LGPL)または getoptpp (GPL)などのさまざまなC++ポートのいずれかを使用できます。

GetOptを使用して必要な(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

さらにもう1つの選択肢は、Lean Mean C++ Option Parserです。

http://optionparser.sourceforge.net

これはヘッダーのみのライブラリ(実際には単一のヘッダーファイル)であり、他のすべての提案とは異なり、独立している、つまり依存関係はまったくありません。特に、STLへの依存はありません。ライブラリのサポートを必要とする例外やその他のものも使用しません。これは、「外部」ライブラリを導入することなく、プレーンCまたは他の言語とリンクできることを意味します。

Boost :: program_optionsのように、そのAPIはオプションへの便利な直接アクセスを提供します。

if(options [HELP])...;

そして

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

Boost :: program_optionsとは異なり、これは(ユーザーが指定した)enumでインデックス付けされた配列を使用しているだけです。これにより、重量のない連想コンテナの利便性が提供されます。

十分に文書化されており、会社に優しいライセンス(MIT)があります。

TLMC++ OPには、行の折り返しや列の配置を行うことができる使用法メッセージ用のニースフォーマッタが含まれています。これは、プログラムがローカライズされている場合に役立ちます。また、80列の使用状況を手動でフォーマットする手間が省けます。

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

}
10
Oliver Nina

AnyOption は、複雑なコマンドラインオプションを簡単に解析するためのC++クラスです。また、オプション値ペア形式のrsourcefileからオプションを解析します。

AnyOptionは、従来のPOSIXスタイルの文字オプション(-n)と新しいGNUスタイルの長いオプション(--name)を実装します。または、POSIXスタイルのオプションを無視するように求めることで、より単純な長いオプションバージョン(-name)を使用できます。

5
Jay

Boostライブラリを使用できる場合は、boost :: program_optionsをお勧めします。

STLにも特定のC++/Cランタイムライブラリにも特定のものはありません。

3
Macke

CLPPライブラリを試してください。コマンドラインパラメーターの解析のためのシンプルで柔軟なライブラリです。ヘッダーのみでクロスプラットフォーム。 ISO C++およびBoost C++ライブラリのみを使用します。私見では、Boost.Program_optionsより簡単です。

ライブラリ: http://sourceforge.net/projects/clp-parser

2010年10月26日-新しいリリース2.0rc。多くのバグが修正され、ソースコード、ドキュメント、例、コメントの完全なリファクタリングが修正されました。

2

かなり遅い回答ですが、いくつかのプロジェクトでGetPotを使用しました: http://getpot.sourceforge.net/

主な機能:すべてが単一のヘッダーファイルにあり、面倒なビルドは不要です。マシンのどこかに保存し、main()を保持しているファイルに「#include」するだけです。

最近更新されていませんが、うまく文書化されており、うまく機能しています。試してみてください。

2
kebs