2009-05-15 19 views
24

Estoy buscando un analizador de línea de comandos para Qt4.Analizador de línea de comandos para Qt4

Hice una pequeña búsqueda en Google, y encontré esto: http://www.froglogic.com/pg?id=PublicationsFreeware&category=getopt sin embargo, carece de soporte para los modificadores "--enable-foo" y "--disable-foo". Además de eso, parece un verdadero ganador.

EDIT:

Parece Frologic elimina esto. Entonces, las mejores opciones que veo son usar Boost (que no es API ni ABI estable) ni forzar el soporte para kdelibs. Yay ...

+0

Para aquellos (como yo) que todavía están en Qt4, la biblioteca frológica se puede obtener utilizando la máquina Wayback de Internet Archive. La licencia en el código frologic es una licencia de estilo BSD de 3 cláusulas, por lo que la mayoría puede usar el código. –

Respuesta

17

Desde Qt 5.2, finalmente puede encontrar una solución en QtCore: he contribuido QCommandLineParser allí.

1

¿Tiene que ser específico de Qt4? Si no, GNU Getopt es realmente agradable, aunque la licencia puede ser un problema si no está haciendo software de código abierto.

+1

Siendo LGPL permite que uno lo use sin tener que abrir el código fuente. ¿Me estoy perdiendo de algo? – Tshepang

+1

LGPL requiere enlace dinámico, lo que no siempre es posible o una buena idea. – Zifre

3

Ese paquete admite --disable-foo y --enable-foo a través de opts.addSwitch ("disable-foo", & foo_disabled); y opts.addSwitch ("enable-foo", & foo_enabled);. Necesita controlar ambos y tratar con alguien que especifique ambos (¡oops!).

Lo que no entiendo es cómo esto tiene algo que ver con QT4 ...

+0

Esto significa que por cada bool necesito agregar dos reglas. No es la mejor práctica. Además, quiero tener una solución Qt4 "nativa". Por ejemplo, cuando agrego un interruptor con valores múltiples, quiero obtener una QList, o cuando digo que quiero un punto, quiero obtener un QPoint. opts.addPoint ("location", myQPointVariable) – elcuco

+0

Sí, eso es cierto, necesita dos "reglas", pero también tiene dos opciones; es --disable-foo no --foo = deshabilitado. Y si tiene ambas, necesita detectar y al menos el error al habilitar y deshabilitarlas juntas (aunque eso podría hacerse en el analizador getopt). La respuesta de ephemient tiene más información específica de QT, pero la biblioteca que sugiere tiene las mismas restricciones generales que la froglogica. Los argumentos QT arguments() no manejan ninguno de los tipos de análisis que desea. – jesup

23

QCoreApplication's constructors requieren (int &argc, char **argv) (y QApplication hereda de QCoreApplication). A medida que el documentation states, es muy recomendable que

Desde QApplication también se ocupa de los argumentos de línea de comando común, por lo general es una buena idea para crearlo antes cualquier interpretación o modificación de argv se realiza en la propia aplicación.

Y si estás dejando Qt obtener el primer paso en el manejo de los argumentos de todos modos, también sería una buena idea utilizar QStringList QCoreApplication::arguments() en lugar de caminar a través argv; QApplication puede eliminar algunos de los argumentos que ha tomado para su propio uso.

Esto no se presta a ser muy compatible con otras bibliotecas de argumentos de análisis ...

Sin embargo, kdelibs viene con un buen analizador argumento, KCmdLineArgs. Es LGPL y se puede usar sin KApplication si realmente desea (llame al 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; 

Untested (¿quién prueba lo que publican en S.O.?).

+3

robando kdelibs ... qué buena idea, ¿cómo no lo pensé? ¡Tendré que probar esto! – elcuco

+0

Estoy arrojando mis puntos de repetición en la pantalla, pero no pasa nada. – UmNyobe

2

Realmente un método simple consiste en escanear "clave = valor" args,
los pusieron en una mesa dicen zz.map: QString -> QVariant,
y obtener sus valores con zz.map.value (clave, defecto). Un ejemplo:

#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 es < 1 página, a continuación; lo mismo para Python ~ 10 líneas.

(Todo el mundo tiene su analizador de opciones favoritas; esta es la más simple.
vale la pena repetir: sin embargo se especifican opciones, ellos eco a los archivos de salida -
"todos los científicos que conozco tiene problemas para hacer el seguimiento de qué parámetros se utilizan última vez que corrió un script")

To. hacer que QPoints funcione, por supuesto, uno necesita un QString -> QPoint parser. ¿Alguien sabe por qué esto no funciona (en Qt 4.4.3)?

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

Agregado 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, ¿dónde puedo obtener esa clase "ztest"? Vea la respuesta de Muby – elcuco

+1

; prefiera llamarla ArgTest, extern ArgTest argTest; – raidsan

0

También para algunas opciones de lujo que se pueden tratar de análisis sintáctico gperf.

IBM tiene un bonito tutorial en él.

+0

GPL, y no LGPL/MIT/X11 .... y sin integración con primitivas Qt4 vea mi comentario en jesup – elcuco

+0

No estoy muy seguro de que la licencia se aplique al código generado por gperf y según mi leal saber y entender no estás enlazando contra gperf. Es solo una herramienta externa para construir una función/objeto de búsqueda. Con toda justicia, todavía tengo que usarlo para un proyecto real. –

2
+1

TAN AGRADABLE !!! parece licencia de BSD'ish, Qt puro ... sin embargo es un poco detallado. Busque, por ejemplo, la cantidad de código necesario para procesar los agrupamientos de la línea de comando: http://code.google.com/p/qtargparser/source/browse/trunk/samples/help/main.cpp Necesito encuentra tiempo y juega con eso. ¡Gracias! – elcuco

+0

Se ve bastante bien, pero no si ve que toda la API usa excepciones. No quiero usar excepciones en un marco que no las use. :( – Tobias

7

Existe también QxtCommandOptions de http://www.libqxt.org/

+1

QxtCommandOptions no parece estar incluido en qxt 0.6 o tip. – maxschlepzig

+1

@maxschlepzig: el encabezado está ahí - probablemente algún error del generador de documentación – alexei

9

Esto es más o menos la misma respuesta que ephemient, pero con una expresión regular simple para ayudar a analizar los argumentos. (De esta manera podría ser útil si sólo necesita un puñado de args)

Ejecutar con esta:

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

Y el código:

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

¿Cómo extendería esto para múltiples argumentos de comando? Expresiones más regulares? – retrodrone

+0

@retrodrone - Agregué más expresiones regulares para aclarar este ejemplo. – Johan

+0

gracias! Sospeché que esta era la solución. – retrodrone

2

Es 2013 y todavía no hay "primera parte" arg parser. Anyways..if alguien encuentra a sí mismos frente al mismo problema y me gustaría evitar las curvas de aprendizaje que vienen con libs cmd analizador, aquí es una solución "rápida & sucia" para usted: -

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

Ejemplo: -

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

Uso:

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` 

Parámetros se puede pasar en cualquier orden

Editar: las actualizaciones de este fragmento serán found here

Cuestiones relacionadas