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 strin
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.
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.
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;
}
}