Які бібліотеки парсера параметрів існують для С ++? [зачинено]


76

Я хотів би передати параметри моїй програмі C ++ наступним чином:

./myprog --setting=value

Чи є бібліотеки, які допоможуть мені це зробити легко?

Див. Також допоміжні засоби для розбору аргументів для C та Unix


1
Нещодавно писав це для сучасного c ++: github.com/juzzlin/Argengine
juzzlin 02.03.20

Відповіді:


45

13
Це здається найбільш очевидним варіантом для C ++, але його документація недостатньо повна. Спробуйте знайти там, як зберігати та отримувати параметри з файлу, що є важливою функцією. Мені не подобається, як виглядає код, що використовує його, зокрема формулювання, options.add_options()(option1)(option2)...яке я вважаю зловживанням граматикою C ++.
gatopeich

8
Компіляція коду за допомогою Boost.Program_options не здавалася прямолінійною і вимагала опцій зв’язування тощо, крім включення файлу заголовка.
Річард

2
Ви можете отримати майже те саме за набагато менше. Якщо ви хочете подібні речі --long-option, це досить просто зробити самостійно.
Луїс Мачука

З одного боку, для дійсно простих програм або ви просто працюєте безпосередньо з масивом argv []. Інша ситуація - для повної гнучкості в аргументах ви можете працювати безпосередньо з масивом argv (ви можете виконати prog -1 firstinput -2 second input -obj {аргументи конструктора ..}). В іншому випадку використовуйте boost, tclap або багато інших.
Kemin Zhou

boost::program_optionsбезнадійно надмірно інженерний, складний у використанні та недокументований. Одна з небагатьох бібліотек Boost, яка отримала б велику користь від повного редизайну та переписування. Не використовуйте його, якщо можете уникнути.
Laryx Decidua

26

GNU GetOpt .

Простий приклад використання GetOpt:

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

// Namespaces:
using namespace std;

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

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

Ви також можете використовувати optarg, якщо у вас є параметри, які приймають аргументи.


14
Тьфу. Я розумію використання цієї бібліотеки в коді C, але IMO, це занадто низький рівень, щоб бути прийнятним у будь-якому додатку C ++, який я коли-небудь писав. Знайдіть кращу бібліотеку, якщо вам не потрібен чистий C.
Томас Едінг,

1
Існує також приклад GNU getopt зі значенням, наприклад myexe -c myvalue. Ви можете спробувати знайти "Приклад синтаксичного аналізу аргументів за допомогою getopt"
edW

ось приклад приклад , наведений сам GNU ^^
finnmglas

19

Мені простіше використовувати ezOptionParser . Це також один файл заголовка, не залежить ні від чого, крім STL, працює для Windows та Linux (дуже ймовірно і для інших платформ), не має кривої навчання завдяки прикладам, має функції інших бібліотек (наприклад, імпорт / експорт файлів) з коментарями, довільними назвами параметрів з роздільниками, автоматичним форматуванням використання тощо) та має ліцензію LGPL.


1
Починаючи з версії 0.1.3, ліцензія тепер є MIT. Я випробовую це на новому проекті замість TCLAP, і поки це виглядає дуже перспективно. Параметр конфігурації файлу досить приємний.
Шон

6
Я щойно випробував exOptionParser, але у нього так багато проблем. Перш за все, я отримую 58 попереджень про непідписану конвертацію int в int. Він також намагається збільшити ітератори списку (які не можна використовувати таким чином) і аварійно завершує роботу. Його інтерфейс також такий жахливий. Він використовує посилання всюди, а не просто повертає потрібні дані. Це схоже на бібліотеку C, хоча вона побудована поверх C ++ STL.
Ендрю Ларссон,

Примітка; виявлення невідомих аргументів не працює. Крім того, заголовок видає помилки компіляції, якщо не розміщений перед іншими заголовками. Я шукатиму ще один парсер ..
Тотте Карлссон,

19

TCLAPце справді приємний легкий дизайн і простий у використанні: http://tclap.sourceforge.net/


4
Я використовував getopt, gflags google, program_options від Boost і tclap - це фантастика . Я не можу сказати достатньо хороших речей про tclap, особливо враховуючи наявні альтернативи. Ступінь прихильностей у мене полягає в тому, що форматування допомоги "відрізняється" від того, до чого звикло моє око.
Шон

16

І є бібліотека Google .

Дійсно, аналіз командного рядка "вирішено". Просто виберіть один.


(Дякую @QPaysTaxes за те, що ви помітили, що посилання було порушено; я не знаю, чому вашу редакцію було відхилено, але ви точно були правильними).
Max Lybbert

5
Я не можу придумати менш корисної відповіді на запитання. 'Це вирішено. Вибрати один.' Вибачте, але "duh". Приблизно за 15 хвилин роздумів над цією проблемою я придумав близько 30 різних сценаріїв того, як можна підійти до неї. Я підозрюю, що "правильна" відповідь більше схожа на пояснення того, як певний набір проблем призведе до певного набору реалізацій коду. Але, ей, дякую за дзвінок.
MarkWayne

10

Я думаю, що GNU GetOpt не надто негайний для використання.

Qt та Boost можуть бути рішенням, але вам потрібно завантажити та скомпілювати багато коду.

Тому я реалізував синтаксичний аналізатор, який створює std :: map <std :: string, std :: string> параметрів.

Наприклад, виклик:

 ./myProgram -v -p 1234

карта буде:

 ["-v"][""]
 ["-p"]["1234"]

Використання:

int main(int argc, char *argv[]) {
    MainOptions mo(argc, argv);
    MainOptions::Option* opt = mo.getParamFromKey("-p");
    const string type = opt ? (*opt).second : "";
    cout << type << endl; /* Prints 1234 */
    /* Your check code */
}

MainOptions.h

#ifndef MAINOPTIONS_H_
#define MAINOPTIONS_H_

#include <map>
#include <string>

class MainOptions {
public:
    typedef std::pair<std::string, std::string> Option;
    MainOptions(int argc, char *argv[]);
    virtual ~MainOptions();
    std::string getAppName() const;
    bool hasKey(const std::string&) const;
    Option* getParamFromKey(const std::string&) const;
    void printOptions() const;
private:
    typedef std::map<std::string, std::string> Options;
    void parse();
    const char* const *begin() const;
    const char* const *end() const;
    const char* const *last() const;
    Options options_;
    int argc_;
    char** argv_;
    std::string appName_;
};

MainOptions.cpp

#include "MainOptions.h"

#include <iostream>

using namespace std;

MainOptions::MainOptions(int argc, char* argv[]) :
        argc_(argc),
        argv_(argv) {
    appName_ = argv_[0];
    this->parse();
}

MainOptions::~MainOptions() {
}

std::string MainOptions::getAppName() const {
    return appName_;
}

void MainOptions::parse() {
    typedef pair<string, string> Option;
    Option* option = new pair<string, string>();
    for (const char* const * i = this->begin() + 1; i != this->end(); i++) {
        const string p = *i;
        if (option->first == "" && p[0] == '-') {
            option->first = p;
            if (i == this->last()) {
                options_.insert(Option(option->first, option->second));
            }
            continue;
        } else if (option->first != "" && p[0] == '-') {
            option->second = "null"; /* or leave empty? */
            options_.insert(Option(option->first, option->second));
            option->first = p;
            option->second = "";
            if (i == this->last()) {
                options_.insert(Option(option->first, option->second));
            }
            continue;
        } else if (option->first != "") {
            option->second = p;
            options_.insert(Option(option->first, option->second));
            option->first = "";
            option->second = "";
            continue;
        }
    }
}

void MainOptions::printOptions() const {
    std::map<std::string, std::string>::const_iterator m = options_.begin();
    int i = 0;
    if (options_.empty()) {
        cout << "No parameters\n";
    }
    for (; m != options_.end(); m++, ++i) {
        cout << "Parameter [" << i << "] [" << (*m).first << " " << (*m).second
                << "]\n";
    }
}

const char* const *MainOptions::begin() const {
    return argv_;
}

const char* const *MainOptions::end() const {
    return argv_ + argc_;
}

const char* const *MainOptions::last() const {
    return argv_ + argc_ - 1;
}

bool MainOptions::hasKey(const std::string& key) const {
    return options_.find(key) != options_.end();
}

MainOptions::Option* MainOptions::getParamFromKey(
        const std::string& key) const {
    const Options::const_iterator i = options_.find(key);
    MainOptions::Option* o = 0;
    if (i != options_.end()) {
        o = new MainOptions::Option((*i).first, (*i).second);
    }
    return o;
}

2
Що ви маєте на увазі під "... не надто негайним для використання" ? Чи можете ви детальніше сказати?
Пітер Мортенсен,


7

Якщо я можу, вдаривши мій власний ріг, я також хотів би запропонувати поглянути на бібліотеку синтаксичного аналізу, яку я написав: dropt .

  • Це бібліотека C (з обгорткою C ++ за бажанням).
  • Він легкий.
  • Він розширюваний (користувацькі типи аргументів можуть бути легко додані та мати рівні умови з вбудованими типами аргументів).
  • Він повинен бути дуже портативним (він написаний на стандартній C), без залежностей (крім стандартної бібліотеки C).
  • Він має дуже обмежену ліцензію (zlib / libpng).

Однією з особливостей, яку пропонує багато інших, є можливість замінити попередні параметри. Наприклад, якщо у вас є псевдонім оболонки:

alias bar="foo --flag1 --flag2 --flag3"

і ви хочете використовувати, barале з --flag1відключеними, це дозволяє зробити:

bar --flag1=0

1
Це виглядає досить акуратно. Радий, що прокрутив вниз; для простого C просто нічого дуже хорошого немає, збережіть це!
Ашера

Звучить чудово, але здається трохи занадто великим. Крім того, я просто шукаю спосіб проаналізувати специфікатори формату scanf з аргументу, я вже написав свій власний (хоча і більш базовий) парсер.
MarcusJ

1
@MarcusJ Здається трохи дивним, що ви говорите, що це занадто велике (воно набагато менше, ніж більшість інших синтаксичних аналізаторів параметрів командного рядка), але все ж ви хочете, щоб воно аналізувало специфікатори формату printf / scanf (а це не те, що командний рядок варіанти парсерів зазвичай роблять) ...
jamesdlin

Так, я знаю, що до цього у мене є певні вимоги, я просто продовжу переписувати мій синтаксичний аналізатор, але я подивився на ваш код, і ідея передати структуру, щоб містити різні параметри, справді цікава (поки що мій просто закодований). Він не надто великий сам по собі, просто у мене є один проект .c / .h, і ваш код подвоїть кількість коду, який я вже отримав, тому він занадто великий для мого конкретного проекту.
MarcusJ

5

Qt 5.2 постачається з API-аналізатором командного рядка .

Невеликий приклад:

#include <QCoreApplication>
#include <QCommandLineParser>
#include <QDebug>

int main(int argc, char **argv)
{
  QCoreApplication app(argc, argv);
  app.setApplicationName("ToolX");
  app.setApplicationVersion("1.2");

  QCommandLineParser parser;
  parser.setApplicationDescription("Tool for doing X.");
  parser.addHelpOption();
  parser.addVersionOption();
  parser.addPositionalArgument("infile",
      QCoreApplication::translate("main", "Input file."));

  QCommandLineOption verbose_opt("+",
      QCoreApplication::translate("main", "be verbose"));
  parser.addOption(verbose_opt);

  QCommandLineOption out_opt(QStringList() << "o" << "output",
      QCoreApplication::translate("main", "Output file."),
      QCoreApplication::translate("main", "filename"), // value name
      QCoreApplication::translate("main", "out")   // default value
      );
  parser.addOption(out_opt);

  // exits on error
  parser.process(app);

  const QStringList args = parser.positionalArguments();

  qDebug() << "Input files: " << args
    << ", verbose: " << parser.isSet(verbose_opt)
    << ", output: " << parser.value(out_opt)
    << '\n';
  return 0;
}

Приклад виводу

Автоматично сформований екран довідки:

$ ./qtopt -h
Використання: ./qtopt [options] infile
Інструмент для виконання X.

Варіанти:
  -h, --help Відображає цю довідку.
  -v, --version Відображає інформацію про версію.
  - + бути багатослівним
  -o, --output Вихідний файл.

Аргументи:
  infile Вхідний файл.

Вихід автоматично виведеної версії:

$ ./qtopt -v
ToolX 1.2

Деякі реальні дзвінки:

$ ./qtopt b1 - + -o tmp blah.foo
Вхідні файли: ("b1", "blah.foo"), детально: true, вихід: "tmp"
$ ./qtopt          
Вхідні файли: (), детальний: false, вихідний: "out"

Помилка синтаксичного аналізу:

$ ./qtopt --hlp
Невідома опція 'hlp'.
$ echo $?
1

Висновок

Якщо ваша програма вже використовує бібліотеки Qt (> = 5.2), її аналіз командного рядка є досить зручним для виконання роботи.

Майте на увазі, що вбудовані параметри Qt споживаються QApplicationдо запуску парсера опцій.


3

argstreamє досить схожим на boost.program_option: він дозволяє прив'язувати змінні до параметрів і т. д. Однак він не обробляє параметри, що зберігаються у файлі конфігурації.


3

Спробуйте бібліотеку CLPP. Це проста та гнучка бібліотека для аналізу параметрів командного рядка. Лише заголовки та крос-платформа. Використовує лише бібліотеки ISO C ++ та Boost C ++. IMHO це простіше, ніж Boost.Program_options.

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

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


1

Ви можете спробувати мій маленький заголовок опцій (166 loc так легко зламати) options.hpp . Це реалізація з одним заголовком, і вона повинна робити те, що ви просите. Він також автоматично надрукує вам сторінку довідки.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.