Парсер командной строки для Qt4

Я ищу парсер командной строки для Qt4.

Я провел небольшой поиск в Google и нашел это: http://www.froglogic.com/pg?id=PublicationsFreeware&category=getopt, однако он не поддерживает переключатели "--enable-foo" и "--disable-foo". Кроме того, он выглядит как настоящий победитель.

РЕДАКТИРОВАТЬ:

Кажется, Frologic удалил это. Таким образом, лучшие варианты, которые я вижу, — это использование Boost (который не является стабильным API или ABI) или разветвление поддержки kdelibs. Ура...


person elcuco    schedule 15.05.2009    source источник
comment
Те, кто (как и я) все еще используют Qt4, могут получить библиотеку frologic с помощью машины Internet Archive Wayback. Лицензия на код frologic представляет собой лицензию в стиле BSD, состоящую из 3 пунктов, поэтому почти каждый может использовать этот код.   -  person Michael Kohne    schedule 28.02.2014


Ответы (11)


Начиная с Qt 5.2 вы, наконец, можете найти решение в самом QtCore: я предоставил QCommandLineParser там.

person David Faure    schedule 04.10.2013

Для конструкторов QCoreApplication требуется (int &argc, char **argv)QApplication наследуется от QCoreApplication). Как указано в документации, настоятельно рекомендуется

Поскольку QApplication также имеет дело с общими аргументами командной строки, обычно рекомендуется создать его прежде в самом приложении будет выполнена какая-либо интерпретация или модификация argv.

И если вы в любом случае позволяете Qt получить первый проход при обработке аргументов, также было бы неплохо использовать QStringList QCoreApplication::arguments() вместо перехода через argv; QApplication может удалить некоторые из аргументов, которые он использует для собственного использования.

Это не очень совместимо с другими библиотеками анализа аргументов...

Тем не менее, kdelibs поставляется с хорошим парсером аргументов, KCmdLineArgs. Это LGPL, и вы можете использовать его без KApplication, если хотите (позвоните KCmdLineArgs::init).

KCmdLineOptions options;
options.add("enable-foo", ki18n("enables foo"));
options.add("nodisable-foo", ki18n("disables foo"));
// double negatives are confusing, but this makes disable-foo enabled by default

KCmdLineArgs::addCmdLineOptions(options);
KApplication app;
KCmdLineArgs *args = KCmdLineArgs::parsedArgs();

if (args->isSet("enable-foo") && !args->isSet("disable-foo"))
    cout << "foo enabled" << endl;
else
    cout << "foo disabled" << endl;

Непроверено (кто когда-либо тестировал то, что они публикуют на S.O.?).

person ephemient    schedule 15.05.2009
comment
срывая kdelibs... какая хорошая идея, как я не подумал об этом? Я должен буду проверить это! - person elcuco; 16.05.2009
comment
Я выбрасываю свои точки повторения на экран, но ничего не происходит. - person UmNyobe; 27.09.2012

Это более или менее тот же ответ, что и ephemient, но с простым регулярным выражением, помогающим анализировать аргументы. (Этот способ может быть полезен, если вам нужно всего несколько аргументов)

Запустите с этим:

./QArgTest --pid=45 --enable-foo

И код:

int main(int argc, char *argv[]) {
    QApplication app(argc, argv, false);
    qDebug() << "QApp arg test app"; 

    QStringList args = app.arguments();

    int pid = 0;

    QRegExp rxArgPid("--pid=([0-9]{1,})");
    QRegExp rxArgFooEna("--enable-foo");
    QRegExp rxArgFooDis("--disable-foo");

    for (int i = 1; i < args.size(); ++i) {
        if (rxArgPid.indexIn(args.at(i)) != -1 ) {   
            pid =  rxArgPid.cap(1).toInt();
            qDebug() << i << ":" << args.at(i) << rxArgPid.cap(1) << pid;
        }
        else if (rxArgFooEna.indexIn(args.at(i)) != -1 ) {   
            qDebug() << i << ":" << args.at(i) << "Enable Foo";
        } 
        else if (rxArgFooDis.indexIn(args.at(i)) != -1 ) {   
            qDebug() << i << ":" << args.at(i) << "Disable Foo";
        } 
        else {
            qDebug() << "Uknown arg:" << args.at(i);
        }
    }
    return 0;
}
person Johan    schedule 21.09.2010
comment
Как бы вы расширили это для нескольких аргументов команды? Больше регулярных выражений? - person retrodrone; 31.07.2011
comment
@retrodrone - я добавил еще несколько регулярных выражений, чтобы прояснить этот пример. - person Johan; 31.07.2011

Также есть QxtCommandOptions из http://www.libqxt.org/.

person KillerWabbit    schedule 06.09.2010
comment
QxtCommandOptions, похоже, не включен в qxt 0.6 или tip. - person maxschlepzig; 13.10.2012
comment
@maxschlepzig: заголовок есть - возможно, какая-то ошибка генератора документации. - person alexei; 18.04.2013

Этот пакет поддерживает --disable-foo и --enable-foo через opts.addSwitch("disable-foo", &foo_disabled); и opts.addSwitch("enable-foo", &foo_enabled);. Вам нужно проверить оба и иметь дело с кем-то, указывающим оба (упс).

Чего я не понимаю, так это как это связано с QT4...

person jesup    schedule 15.05.2009
comment
Это означает, что для каждого bool мне нужно добавить два правила. Не лучшая практика. Кроме того, я хочу иметь собственное решение Qt4. Например, при добавлении переключателя с несколькими значениями я хочу получить QList, или, говоря, что мне нужна точка, я хочу получить QPoint. opts.addPoint(местоположение, myQPointVariable) - person elcuco; 15.05.2009
comment
Да, это правда, вам нужно два правила, но у вас также есть два варианта; это --disable-foo, а не --foo=disabled. И если у вас есть и то, и другое, вам нужно обнаружить и, по крайней мере, ошибку при включении и отключении вместе (хотя это можно сделать в парсере getopt). ephemient answer содержит больше информации, специфичной для QT, но предлагаемая им библиотека имеет те же общие ограничения, что и библиотека froglogic. Материал аргументов QT() не обрабатывает какой-либо тип синтаксического анализа, который вы хотите. - person jesup; 16.05.2009

Посмотрите на это: http://code.google.com/p/qtargparser/

person Igor    schedule 21.11.2009
comment
ТАК МИЛО!!! похоже на лицензию BSD, чистый Qt... однако это довольно многословно. Посмотрите, например, объем кода, необходимый для обработки аргументов командной строки: code.google.com/p/qtargparser/source/browse/trunk/samples/help/ Мне нужно найти время и поиграть с ним. Спасибо! - person elcuco; 22.11.2009
comment
Выглядит неплохо, но нет, если вы видите, что весь API использует исключения. Я не хочу использовать исключения в фреймворке, который их не использует. :( - person Tobias; 24.01.2011

Очень простой способ — просмотреть аргументы «ключ = значение»,
поместить их в таблицу, скажем, zz.map: QString -> QVariant,
и получить их значения с помощью zz.map.value(key, default) . Пример:

#include "ztest.h"
Ztest zz;  
int main( int argc, char* argv[] )
{
    zz.eqargs( ++ argv );  // scan  test=2 x=str ... to zz.map

    QString xx = zz.map.value( "xx", "" );
    if( Zint( Size, 10 ))  // a #def -> zz.map.value( "Size", 10 )
        ...

ztest.h это ‹ 1 страница, ниже; то же самое для Python ~ 10 строк.

(У каждого есть свой любимый анализатор опций; этот примерно самый простой.
Стоит повторить: как бы вы ни указывали опции, отображать их в выходных файлах --
"каждый известный мне ученый имеет проблемы с отслеживанием того, какие параметры они использовали в последний раз, когда запускали скрипт».)

Чтобы заставить работать QPoints и т. д., конечно, нужен синтаксический анализатор QString -> QPoint. Кто-нибудь знает, почему это не работает (в Qt 4.4.3)?

QPoint pt(0,0);
QDataStream s( "QPoint(1,2)" );
s >> pt;
qDebug() << "pt:" << pt;  // QPoint(1364225897,1853106225) ??

Добавлено 25 ноября --

// ztest.h: scan args x=2 s=str ... to a key -> string table
// usage:
// Ztest ztest;
// int main( int argc, char* argv[] )
// {
//     QApplication app( argc, argv );
//     ztest.eqargs( ++ argv );  // scan leading args name=value ...
//     int x = Zint( x, 10 );  // arg x= or default 10
//     qreal ff = Zreal( ff, 3.14 );
//     QString s = Zstr( s, "default" );
// care: int misspelled = Zint( misspellled ) -- you lose
//version: 2009-06-09 jun denis

#ifndef ztest_h
#define ztest_h

#include <QHash>
#include <QString>
#include <QVariant>
#include <QRegExp>

//------------------------------------------------------------------------------
class Ztest {
public:
  QHash< QString, QVariant > map;
  int test;  // arg test=num,  if( ztest.test )

  Ztest() : test( 0 ) {}

  QVariant val( const QString& key, const QVariant& default_ = 0 )
  {
    return map.value( key, default_ );
  }

  void setval( const QString& key, const QVariant& val )
  {
    map[key] = val;
    if( key == "test"  ||  key == "Test" )
        test = val.toInt();
  }

//------------------------------------------------------------------------------
    // ztest.eqargs( ++ argv )  scans test=2 x=3 ... -> ztest table
  void eqargs( char** argv )
  {
    char** argv0 = argv;
    char *arg;
    QRegExp re( "(\\w+)=(.*)" );  // name= anything, but not ./file=name
    for( ; (arg = *argv) && re.exactMatch( arg );  argv ++ ){
        setval( re.cap(1), re.cap(2) );
    }
        // change argv[0..] -> args after all name=values
    while(( *argv0++ = *argv++) != 0 ) {}
  }
};

extern Ztest ztest;

    // macros: int x = Zint( x, 10 ): x= arg or default 10
#define Zstr( key, default )    ztest.val( #key, default ).toString()
#define Zint( key, default )    ztest.val( #key, default ).toInt()
#define Zreal( key, default )   ztest.val( #key, default ).toDouble()

#endif
person denis    schedule 09.06.2009
comment
Денис, где я могу получить этот класс ztest? Смотрите ответ Муби - person elcuco; 22.11.2009
comment
предпочитаю называть его ArgTest, extern ArgTest argTest; - person raidsan; 15.10.2012

На дворе 2013 год, а синтаксического анализатора аргументов до сих пор нет. В любом случае ... если кто-то столкнулся с той же проблемой и хотел бы избежать кривых обучения, которые идут с библиотеками парсера cmd, вот вам «быстрое и грязное» исправление: -

QString QArgByKey(QString key, QChar sep = QChar('\0') ) //prototype usually in separate header

QString QArgByKey(QString key, QChar sep )
{
    bool sepd=sep!=QChar('\0');
    int pos=sepd?qApp->arguments().indexOf(QRegExp('^'+key+sep+"\\S*")):qApp->arguments().indexOf(QRegExp(key));
    return pos==-1?QString::null:
    (sepd?qApp->arguments().at(pos).split(sep).at(1):(++pos<qApp->arguments().size()?qApp->arguments().at(pos):QString::null));
}

Пример:-

user@box:~$ ./myApp  firstKey=Value1 --secondKey Value2 thirdKey=val3.1,val3.2,val3.3 --enable-foo

Применение:

QString param1   = QArgByKey("firstkey",'='); // Returns `Value1` from first pair
QString param2   = QArgByKey("--secondkey"); // Returns `Value2` from second pair
QString param3-1 = QArgByKey("thirdkey",'=').split(',').at(0); // Returns `val3.1`
bool fooEnabled  = qApp->arguments().contains("--enable-foo"); //To check for `--enable-foo` 

Параметры можно передавать в любом порядке

Изменить: обновления этого фрагмента можно найти здесь

person mrmoje    schedule 01.09.2013

Должен ли он быть специфичным для Qt4? Если нет, GNU Getopt действительно хорош, хотя лицензирование может быть проблемой, если вы не делаете программное обеспечение с открытым исходным кодом.

person Zifre    schedule 15.05.2009
comment
Наличие LGPL позволяет использовать его без необходимости открывать исходный код. Я что-то пропустил? - person tshepang; 12.07.2013
comment
LGPL требует динамического связывания, что не всегда возможно или является хорошей идеей. - person Zifre; 13.07.2013

Также для парсинга некоторых причудливых вариантов вы можете попробовать gperf.

У IBM есть хорошее руководство по этому вопросу.

person Marius Or.    schedule 10.11.2009
comment
GPL, а не LGPL/MIT/X11.... и отсутствие интеграции с примитивами Qt4 см. мой комментарий к jesup - person elcuco; 12.11.2009
comment
Я не очень уверен, что лицензия распространяется на код, сгенерированный gperf, и, насколько мне известно, вы не связываетесь с gperf. Это просто внешний инструмент для создания функции/объекта поиска. Честно говоря, мне еще предстоит использовать его для реального проекта. - person Marius Or.; 15.11.2009

Еще один вариант, с которым я столкнулся, пытаясь сделать это:

http://code.google.com/p/qgetopts/

Я не использовал его, хотя.

person dwj    schedule 16.07.2010