2009-05-15 14 views
24

Sto cercando un parser da riga di comando per Qt4.parser da riga di comando per Qt4

Ho fatto una piccola ricerca su google e ho trovato questo: http://www.froglogic.com/pg?id=PublicationsFreeware&category=getopt tuttavia manca il supporto per le opzioni "--enable-foo" e "--disable-foo". Oltre a ciò, sembra un vero vincitore.

EDIT:

Sembra Frologic rimosso questo. Quindi le migliori opzioni che vedo stanno usando Boost (che non è API o stabile ABI) o che forgiano il supporto per kdelibs. Yay ...

+0

Per quelli (come me) ancora su Qt4, la libreria frologic può essere ottenuta utilizzando la macchina Wayback di Internet Archive. La licenza sul codice frolog è una licenza in stile BSD a 3 clausole, quindi chiunque può usare il codice. –

risposta

17

Dal momento che Qt 5.2 si può finalmente trovare una soluzione in QtCore sé: ho contribuito QCommandLineParser lì.

1

Dev'essere specifico per Qt4? In caso contrario, GNU Getopt è davvero bello, anche se le licenze potrebbero essere un problema se non si sta facendo software open source.

+1

Essendo LGPL consente di usarlo senza dover aprire il codice sorgente. Mi sto perdendo qualcosa? – Tshepang

+1

LGPL richiede il collegamento dinamico, che non è sempre possibile o una buona idea. – Zifre

3

Tale pacchetto supporta --disable-foo e --enable-foo tramite opts.addSwitch ("disable-foo", & foo_disabled); e opts.addSwitch ("enable-foo", & foo_enabled);. È necessario gestire il controllo di entrambi e trattare con qualcuno che specifica entrambi (oops).

Quello che non capisco è come questo abbia a che fare con QT4 ...

+0

Ciò significa che per ogni bool devo aggiungere due regole. Non è la migliore pratica. Inoltre, voglio avere una soluzione Qt4 "nativa". Ad esempio, quando aggiungo uno switch con più valori, voglio ottenere una QList, o quando dico che voglio un punto, voglio ottenere un QPoint. opts.addPoint ("location", myQPointVariable) – elcuco

+0

Sì, è vero, hai bisogno di due "regole" - ma hai anche due opzioni; è --disable-foo not --foo = disabilitato. E se si dispone di entrambi, è necessario rilevare e almeno l'errore di abilitare e disabilitare insieme (anche se potrebbe essere fatto nel parser getopt). La risposta dell'efémient ha più informazioni specifiche QT, ma la libreria che suggerisce ha le stesse restrizioni generali di quella froglogica. Gli argomenti QT() non gestiscono alcun tipo di analisi che si desidera. – jesup

23

QCoreApplication's constructors richiedono (int &argc, char **argv) (e QApplication eredita da QCoreApplication). Come il documentation states, è altamente raccomandato che

Dal QApplication si occupa anche di argomenti della riga di comando più comuni, di solito è una buona idea di crearla prima qualsiasi interpretazione o la modifica dei argv è fatto in l'applicazione stessa.

E se si sta lasciando Qt ottenere il primo passaggio a gestire argomenti in ogni modo, sarebbe anche una buona idea usare QStringList QCoreApplication::arguments() invece di camminare attraverso argv; QApplication può rimuovere alcuni degli argomenti che ha preso per il proprio uso.

Questo non si presta ad essere molto compatibile con altre biblioteche argomento-analisi ...

Tuttavia, kdelibs viene fornito con un bel parser argomento, KCmdLineArgs. È LGPL e può essere utilizzato senza KApplication se lo si desidera realmente (chiamare 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; 

Non testato (chi mette mai alla prova quello che pubblicano su S.O.?).

+3

strappa via kdelibs ... che bella idea, come non ci ho pensato? Dovrò provare questo! – elcuco

+0

Sto gettando i miei punti rep sullo schermo ma non succede nulla. – UmNyobe

2

Davvero un metodo semplice è quello di eseguire la scansione di "chiave = valore" args,
metterli in una tabella dicono zz.map: QString -> QVariant,
e ottenere i loro valori con zz.map.value (chiave, predefinito). Un esempio:

#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 pagina, sotto; lo stesso per Python ~ 10 linee.

(Ognuno ha il suo parser di opzioni preferito; questo è il più semplice.
Vale la pena ripetere: tuttavia di specificare le opzioni, loro eco al file di output-
"ogni scienziato che conosco ha difficoltà a tenere traccia di quali parametri hanno usato l'ultima volta che correvano uno script")

To. fare QPoints, ecc lavoro, ovviamente ha bisogno di un QString -> QPoint parser. Qualcuno sa perché questo non funziona (in Qt 4.4.3)?

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

Aggiunto 25nov -

// 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 
+0

Denis, dove posso ottenere quella classe "ztest"? Vedi la risposta di Muby – elcuco

+1

preferisci chiamarla ArgTest, extern ArgTest argTest; – raidsan

0

Anche per alcune opzioni di fantasia si può provare parsing gperf.

IBM ha un bel tutorial su di esso.

+0

GPL, e non LGPL/MIT/X11 .... e nessuna integrazione con Qt4 "primitive" vedi il mio commento a jesup – elcuco

+0

Non sono molto sicuro che la licenza si applichi al codice generato da gperf e al meglio delle mie conoscenze non ti stai collegando a gperf. È solo uno strumento esterno per creare una funzione/oggetto di ricerca. In tutta onestà, devo ancora usarlo per un progetto reale. –

2
+1

COSÌ BELLO !!! sembra una licenza BSD, pura Qt ... comunque è un po 'prolisso. Guarda ad esempio la quantità di codice necessaria per elaborare gli strumenti della riga di comando: http://code.google.com/p/qtargparser/source/browse/trunk/samples/help/main.cpp I do need to trova il tempo e gioca con esso. Grazie! – elcuco

+0

Sembra abbastanza bello, ma non se vedi che l'intera API usa Eccezioni. Non voglio usare Eccezioni in un Framework che non le usa. :( – Tobias

7

C'è anche QxtCommandOptions da http://www.libqxt.org/

+1

QxtCommandOptions non sembra essere incluso in qxt 0.6 o suggerimento – maxschlepzig

+1

@maxschlepzig: l'header è lì - probabilmente qualche errore di generatore di documentazione – alexei

9

Questo è più o meno la stessa risposta ephemient, ma con una semplice espressione regolare per aiutare analizzare i args. (In questo modo potrebbe essere utile se avete solo bisogno di una manciata di args)

Run con questo:

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

E il codice:

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

Come estendere questo per più comandi di comando? Altre espressioni regolari? – retrodrone

+0

@retrodrone - Ho aggiunto un po 'di espressioni regolari per chiarire questo esempio: – Johan

+0

grazie! Ho sospettato che questa fosse la soluzione – retrodrone

2

E 'il 2013 e ancora "1st party" pars pars. Anyways..if qualcuno trova ad affrontare lo stesso problema e vorrei evitare le curve di apprendimento che vengono con librerie cmd parser, qui è una soluzione "rapida & sporco" per voi: -

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

Esempio: -

[email protected]:~$ ./myApp firstKey=Value1 --secondKey Value2 thirdKey=val3.1,val3.2,val3.3 --enable-foo 

Usage:

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` 

Parametri possono essere passati in qualsiasi ordine

Edit: Gli aggiornamenti a questo frammento saranno found here

Problemi correlati