Как анализировать аргументы командной строки на С++?

Возможный дубликат:
Какие библиотеки парсеров для языка существуют для С++?

Каков наилучший способ анализа аргументов командной строки на С++, если указанная программа для запуска следующим образом:

prog [-abc] [input [output]]

Есть ли библиотека в STL для этого?


по теме:

Ответ 2

Предложения для boost::program_options и GNU getopt являются хорошими.

Однако для простых параметров командной строки я обычно использую std:: find

Например, чтобы прочитать имя файла после аргумента командной строки -f. Вы также можете просто определить, была ли опция с одним словом передана как -h для справки.

#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:: strings как значение для std:: find, иначе проверка равенства выполняется по значениям указателя.


Я надеюсь, что это нормально отредактировать этот ответ, вместо этого добавив новый, поскольку это основано на исходном ответе. Я немного переписал функции и инкапсулировал их в класс, так что вот код. Я учил, что было бы целесообразно использовать его так же:

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

Ответ 3

Я могу предложить Templatized С++ Command 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; }
}

Ответ 4

Вы можете использовать GNU GetOpt (LGPL) или один из различных портов С++, например getoptpp (GPL).

Простой пример использования GetOpt из того, что вы хотите (prog [-ab]):

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

Ответ 5

Еще одной альтернативой является Paraner Paralleler Lean Mean С++:

http://optionparser.sourceforge.net

Это библиотека только для заголовков (на самом деле это только один файл заголовка), и в отличие от всех других предложений также автономный, то есть он не имеет никаких зависимостей. В частности, нет никакой зависимости от STL. Он даже не использует исключения или что-то еще, что требует поддержки библиотеки. Это означает, что он может быть связан с обычным C или другими языками без введения "чужих" библиотек.

Как и boost:: program_options, его API предлагает удобный прямой доступ к параметрам, то есть вы можете написать код, подобный этому

if (опции [HELP])...;

и

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

В отличие от boost:: program_options, это просто использует массив, проиндексированный с перечислением (предоставленным пользователем). Это обеспечивает удобство ассоциативного контейнера без веса.

Он хорошо документирован и имеет дружественную к компании лицензию (MIT).

TLMС++ OP содержит красивый форматтер для сообщений об использовании, которые могут выполнять line-wrapping и выравнивание столбцов, что полезно, если вы локализируете свою программу, потому что она гарантирует, что результат будет хорошо смотреться даже на языках с более длинными сообщениями. Это также избавляет вас от необходимости вручную форматировать ваше использование для 80 столбцов.

Ответ 6

AnyOption - это класс С++ для простого анализа сложных параметров командной строки. Он также анализирует параметры из файла rsourcefile в формате пары значений параметра.

AnyOption реализует традиционные параметры символа стиля POSIX (-n), а также новые варианты длинного стиля GNU (--name). Или вы можете использовать более простую длинную опционную версию (-name), попросив игнорировать параметры стиля POSIX.

Ответ 7

Я бы рекомендовал boost:: program_options, если вы можете использовать Boost lib.

В STL нет ничего конкретного и в обычных версиях С++/C runtime.

Ответ 8

Попробуйте библиотеку CLPP. Это простая и гибкая библиотека для синтаксического анализа параметров командной строки. Только для заголовков и кросс-платформенных. Использует только библиотеки ISO С++ и Boost С++. ИМХО это проще, чем Boost.Program_options.

Библиотека: http://sourceforge.net/projects/clp-parser

26 октября 2010 г. - новый выпуск 2.0rc. Исправлено множество ошибок, исправлен полный рефакторинг исходного кода, документация, примеры и комментарии.

Ответ 9

Довольно поздний ответ, но я использовал GetPot для некоторых проектов: http://getpot.sourceforge.net/

Основная особенность: все в одном файле заголовка, без сбоев сборки. Просто сохраните его где-нибудь на своей машине и "#include" в файле main()

Не обновляется в последнее время, но красиво оформлено и работает хорошо. Вы можете попробовать.

Ответ 10

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

}