Reputation: 4617
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
Upvotes: 3
Views: 2904
Reputation: 33579
QStringList argumentsList = QProcess::splitCommand(arguments);
https://doc.qt.io/qt-5/qprocess.html#splitCommand
Upvotes: 0
Reputation: 207
Extract parameters from string, included quoted regions, in Qt
When parsing any "escaped" or quoted string: splitArgs
(from KF5) was immensely useful.
The following source code manages "escaping" and more; from
one two a\ b "c d e"
it prints
one
two
a b
c d e
The core of the source code is just a splitArgs
call:
#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;
}
}
Upvotes: 1
Reputation: 98425
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.
Upvotes: 7
Reputation: 144
I'm not familiar with the particulars of Qt, however with a quick look at the documentation for QString, here, I believe that the following code should work (albeit inefficiently).
#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
}
Again, I do not use any Qt libraries, and this code is untested, but, if I understand the documentation, it should work.
As far as the -p 4
bit goes, that is not possible with your current syntax for the other arguments.
Upvotes: 2