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:
-
Splitting of the command line into arguments. This needs to be implemented from scratch.
-
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)