在Qt中从字符串(包括引用的区域)中提取参数

时间:2014-07-31 20:53:49

标签: c++ regex qt split

我有一个Qt5 / C ++程序,它接收一个包含程序名称和可能参数的QString。我需要将此QString拆分为多个字符串。例如,字符串

/tmp/myprog --param1 --param2=2 --param3="1 2 3" -p 4

应分成:

list[0]=/tmp/myprog
list[1]=--param1
list[2]=--param2=2
list[3]=--param3="1 2 3"
list[4]=-p 4

我的第一个想法是在空格上使用“split”方法,但这会破坏引用的param3。同样,参数4在-p和4之间没有:或=。

有一种简单的方法吗?我怀疑-p 4不可能轻易拆分,因为无法知道下面的两个项目是否在一起。

但是有分裂/正则表达式/其他方式来分割上述内容吗? (如果我们忽略-p 4是否可能?)


更新

相同的函数可以在没有--param或-p的情况下拆分字符串吗? <串口

abc "a a" "b b b"  c

会变成

list[0]=abc
list[1]="a a"
list[2]="b b b"
list[3]=c

3 个答案:

答案 0 :(得分:7)

您的任务有两个方面:

  1. 将命令行拆分为参数。这需要从头开始实施。

  2. 处理提取参数及其值的参数。从Qt 5.2开始,您可以使用QCommandLineParser来执行此操作。

  3. #include <QCoreApplication>
    #include <QCommandLineParser>
    #include <QDebug>
    
    static QStringList splitCommandLine(const QString & cmdLine)
    {
        QStringList list;
        QString arg;
        bool escape = false;
        enum { Idle, Arg, QuotedArg } state = Idle;
        foreach (QChar const c, cmdLine) {
            if (!escape && c == '\\') { escape = true; continue; }
            switch (state) {
            case Idle:
                if (!escape && c == '"') state = QuotedArg;
                else if (escape || !c.isSpace()) { arg += c; state = Arg; }
                break;
            case Arg:
                if (!escape && c == '"') state = QuotedArg;
                else if (escape || !c.isSpace()) arg += c;
                else { list << arg; arg.clear(); state = Idle; }
                break;
            case QuotedArg:
                if (!escape && c == '"') state = arg.isEmpty() ? Idle : Arg;
                else arg += c;
                break;
            }
            escape = false;
        }
        if (!arg.isEmpty()) list << arg;
        return list;
    }
    
    int main(int argc, char * argv[])
    {
        QCoreApplication app(argc, argv);
        QCommandLineParser parser;
        parser.addHelpOption();
        QCommandLineOption param1("param1");
        QCommandLineOption param2("param2", "", "val2");
        QCommandLineOption param3("param3", "", "val3");
        QCommandLineOption param4("p", "", "val4");
        parser.addOption(param1);
        parser.addOption(param2);
        parser.addOption(param3);
        parser.addOption(param4);
        if (true) {
            // Parse a string
            QString cmdLine("/tmp/myprog --param1 --param2=2\\ 2 --param3=\"1 2 3\" -p 4");
            parser.parse(splitCommandLine(cmdLine));
        } else {
            // Parse a command line passed to this application
            parser.process(app);
        }
        if (parser.isSet(param1)) qDebug() << "param1";
        if (parser.isSet(param2)) qDebug() << "param2:" << parser.value(param2);
        if (parser.isSet(param3)) {
            QStringList values = parser.value(param3)
                    .split(' ', QString::SkipEmptyParts);
            qDebug() << "param3:" << values;
        }
        if (parser.isSet(param4)) qDebug() << "param4:" << parser.value(param4);
        return 0;
    }
    

    输出:

    param1
    param2: "2 2"
    param3: ("1", "2", "3")
    param4: "4"
    

    QDebug引用它输出的字符串。字符串本身不包含任何引号。

答案 1 :(得分:2)

我不熟悉Qt的细节,但是快速查看QString的文档here,我相信下面的代码应该工作(虽然效率低下)

#include<QString>
#include<vector>

vector<QString> list; //vector used for variable length parameter requirements
QString args; //The arguments string
bool quoteFlag = false;
for(int i=0; i<args.size(); i++){
    QString qstr = "";
    while(args.at(i) != QChar(' ') || quoteFlag){ //loops if character is not ' ' or is within a set of quotes
        if(args.at(i) == QChar('\"'){
            quoteFlag = !quoteflag; //basically says, "you are now within a set of quotes"
        }
        qstr += args.at(i); //add current character to qstr
        i++
    }
    list.push_back(qstr) //add qstr to the argument list
}

同样,我不使用任何Qt库,并且此代码未经测试,但是,如果我理解文档,那么应该工作。

-p 4位而言,使用当前其他参数的语法是不可能的。

答案 2 :(得分:0)

  

从Qt

中的字符串,包含的引用区域中提取参数

解析任何“转义”或引用的字符串时:splitArgs(来自KF5)非常有用。

以下源代码管理“转义”等等;来自

    one two a\ b "c d e"

打印

    one
    two
    a b
    c d e

源代码的核心只是splitArgs调用:

#include <QTextStream>
#include <KShell>

int main()
{
    QString whole = "one two a\\ b \"c d e\"";
    QTextStream(stdout) << whole << endl << "--------------------" << endl;

    QStringList group = KShell::splitArgs("one two a\\ b \"c d e\"");
    for (auto element: group) {
        QTextStream(stdout) << element << endl;
    }
}