[SOLVED] Extract parameters from string, included quoted regions, in Qt

Issue

I have a Qt5/C++ program which receives a QString containing a program name and possibly parameters. I need to split this QString into multiple strings. For example, the string

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

Should split into:

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

My first thought was to use the “split” method on a space, but that would break param3 which is quoted. As well parameter 4 has no : or = between the -p and 4.

Is there a simple way to do this? I suspect the -p 4 is impossible to split up easily since there is no way of knowing if the 2 items below together.

But is there a split/regex/other way to split the above? (If we ignore the -p 4 is it possible?)


Update:

Could the same function split the string without the –param or -p? so a string of

abc "a a" "b b b"  c

would become

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

Solution

There are two aspects of your task:

  1. Splitting of the command line into arguments. This needs to be implemented from scratch.

  2. Processing of the arguments to extract parameters and their values. Since Qt 5.2, you can use QCommandLineParser to do that.

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

Output:

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

QDebug quotes the strings it outputs. The strings themselves don’t contain any quotes.

Answered By – Kuba hasn't forgotten Monica

Answer Checked By – Senaida (BugsFixing Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *