2009-05-15 17 views
24

Szukam parsera wiersza poleceń dla Qt4.Analizator wiersza polecenia dla Qt4

Zrobiłem małe wyszukiwanie google i okazało się, że: http://www.froglogic.com/pg?id=PublicationsFreeware&category=getopt jednak brakuje w nim obsługi przełączników "--enable-foo" i "--disable-foo". Poza tym wygląda na prawdziwego zwycięzcę.

EDIT:

Wydaje Frologic usunięte to. Najlepsze opcje, jakie widzę, to użycie funkcji Boost (która nie jest API ani stabilna ABI) lub rozwidlenie obsługi kdelibs. Yay ...

+0

Dla tych (jak ja) wciąż na Qt4, biblioteka frologiczna może być uzyskana za pomocą maszyny internetowej Archive Wayback. Licencja na kod frologiczny jest 3-klauzulową licencją typu BSD, więc większość osób może korzystać z tego kodu. –

Odpowiedz

17

Od Qt 5.2 możesz w końcu znaleźć rozwiązanie w samym QtCore: dostarczyłem tam QCommandLineParser.

1

Czy musi to być specyfikacja Qt4? Jeśli nie, GNU Getopt jest naprawdę niezły, chociaż licencjonowanie może stanowić problem, jeśli nie korzystasz z oprogramowania open source.

+1

Bycie LGPL pozwala używać go bez konieczności otwierania kodu źródłowego. Czy czegoś brakuje? – Tshepang

+1

LGPL wymaga dynamicznego łączenia, co nie zawsze jest możliwe lub dobrym pomysłem. – Zifre

3

Ten pakiet obsługuje -disable-foo i -enable-foo przez opts.addSwitch ("disable-foo", & foo_disabled); i opts.addSwitch ("enable-foo", & foo_enabled);. Musisz obsłużyć sprawdzanie obu i radzenie sobie z osobą określającą oba (oops).

Co ja nie rozumiem, w jaki sposób ma to nic wspólnego z QT4 ...

+0

Oznacza to, że dla każdego boola muszę dodać dwie reguły. To nie najlepsza praktyka. Poza tym chcę mieć "rodzime" rozwiązanie Qt4. Na przykład, dodając przełącznik z wieloma wartościami, chcę uzyskać QList, lub mówiąc, że chcę punkt, chcę uzyskać QPoint. opts.addPoint ("location", myQPointVariable) – elcuco

+0

Tak, to prawda, potrzebujesz dwóch "reguł" - ale masz też dwie opcje; to jest --disable-foo nie - foo = wyłączone. A jeśli masz oba, musisz wykryć i przynajmniej błąd przy włączaniu i wyłączaniu razem (chociaż można to zrobić w parserze getopt). Odpowiedź Ephemienta zawiera więcej informacji na temat QT, ale sugerowana przez niego biblioteka ma takie same ogólne ograniczenia, jak w przypadku tej żabogicznej. Argumenty QT arguments() nie obsługują żadnego rodzaju analizowania. – jesup

23

QCoreApplication's constructors wymagają (int &argc, char **argv) (i QApplication dziedziczy QCoreApplication). Jako documentation states, jest wysoce zalecane,

Od QApplication zajmuje się również linia argumentacji wspólnego dowodzenia, to zwykle dobry pomysł, aby go utworzyć przed żadnej interpretacji lub modyfikacja argv odbywa się w samej aplikacji.

A jeśli pozwalając Qt dostać pierwszego przejścia na obsługę argumentów jakikolwiek byłoby również dobrym pomysłem jest użycie QStringList QCoreApplication::arguments() zamiast chodząc argv; QApplication może usunąć niektóre z argumentów, które podjął dla własnego użytku.

ten nie nadaje się do bycia bardzo kompatybilny z innymi bibliotekami argumentów-parsowania ...

Jednak kdelibs nie pochodzi z ładnym parsera argument KCmdLineArgs. Jest to LGPL i może być używany bez KApplication, jeśli naprawdę chcesz (zadzwoń pod numer 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; 

Nienormowany (kto kiedykolwiek przetestuje to, co pisze na S.O.?).

+3

zgrywanie kdelibs ... co za fajny pomysł, jak o tym nie pomyślałem? Będę musiał to przetestować! – elcuco

+0

Rzucam moje punkty rep na ekranie, ale nic się nie dzieje. – UmNyobe

2

bardzo prosty sposób jest skanowanie „klucz = wartość” args,
umieścić je w tabeli powiedzieć zz.map: QString -> QVariant,
i uzyskać ich wartości z zz.map.value (klucz, domyślna). Przykład:

#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 jest < 1 stronie, poniżej; to samo dla Pythona ~ 10 linii.

(Każdy ma swój ulubiony parser opcji; ten jest najprostszy.
warto powtarzać: jednak określić opcje, echo ich do plików wyjściowych -
„każdy naukowiec wiem, ma problemy z utrzymaniem toru co Parametry używali ostatnim razem pobiegli skrypt”)

TO. sprawić, że QPoints itp. działają, oczywiście, potrzebuje parsera QString -> QPoint. Ktoś wie od ręki, dlaczego to nie działa (w Qt 4.4.3)?

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

Dodany 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, gdzie mogę uzyskać tę klasę "ztest"? Zobacz odpowiedź Muby'ego – elcuco

+1

preferuj nazwę ArgTest, extern ArgTest argTest; – raidsan

0

Również niektóre fantazyjne opcje analizowania można spróbować gperf.

IBM ma na sobie ładny tutorial.

+0

GPL, a nie LGPL/MIT/X11 .... i brak integracji z prymitywami Qt4 zobacz mój komentarz do jesup – elcuco

+0

Nie jestem pewien, czy licencja dotyczy kodu wygenerowanego przez gperf i zgodnie z moją najlepszą wiedzą nie łączysz się z gperf. Jest to tylko zewnętrzne narzędzie do budowania funkcji/obiektu wyszukiwania. Przy całej uczciwości, nie wykorzystałem go do rzeczywistego projektu. –

2
+1

TAK ŁADNE !!! wydaje się być licencją BSD, czystym Qt ... jednak jest trochę gadatliwy. Poszukaj na przykład ilości kodu potrzebnego do przetworzenia na serwerach wiersza poleceń: http://code.google.com/p/qtargparser/source/browse/trunk/samples/help/main.cpp Potrzebuję znajdź czas i baw się z nim. Dzięki! – elcuco

+0

Wygląda całkiem ładnie, ale nie, jeśli widzisz, że całe API używa wyjątków. Nie chcę używać wyjątków w strukturze, która ich nie używa. :( – Tobias

9

To jest mniej więcej taka sama odpowiedź jak ephemient, ale z prostym regexp pomóc analizować args. (W ten sposób może być przydatna, gdy trzeba tylko garść args)

Run z tym:

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

I kod:

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

Jak rozszerzyć to dla wielu argumentów polecenia? Więcej wyrażeń regularnych? – retrodrone

+0

@retrodrone - Dodałem trochę więcej wyrażeń, aby wyjaśnić ten przykład: – Johan

+0

dziękuję! Podejrzewałem, że to jest rozwiązanie – retrodrone

2

To 2013 i nadal nie ma "1st Party" arg parser. Anyways..if ktoś znajdzie się w obliczu tego samego problemu i chciałby uniknąć krzywe uczenia się, które pochodzą z bibliotekami parsera cmd, tutaj jest „szybkie & brudne” fix dla Ciebie: -

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

Przykład: -

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

Zastosowanie:

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` 

Params mogą być przekazywane w dowolnej kolejności

Edytuj: Uaktualnienia do tego fragmentu będą następujące: found here

Powiązane problemy