PDA

View Full Version : Is it possible to use QString::contains(QRegExp) in a switch statement?



positive_4_life
2nd March 2011, 16:39
Say I'm reading a file, line by line, and I want to check if the line QString satisfies any QRegExp I have defined.

I could use a bunch of if statements such as :


while(!in.EOF)
{
line = in.readLine();

if(line.contains(RegExp1)){...}
else if(line.contains(RegExp2){...}
...
else if(line.contains(RegExpN){...}
}


But I thought it would be neater to write it in the format of a switch. Can this be done. I've googled, but it gives no relevant results.

I thought I could have done something like this:



while(!in.EOF)
{
switch(true)
{
case line.contains(RegExp1): {...}
...
case line.contains(RegExpN): {...}
}
}

Doesn't work though.

mcosta
2nd March 2011, 17:04
HI,

in C++ the case argument MUST be an INTEGER (char, short, int, ...)

wysota
2nd March 2011, 17:56
If you are sure each line will satisfy only one regular expression, you can do:

int mask = 0;
mask |= line.contains(rx1) << 1;
mask |= line.contains(rx2) << 2;
mask |= line.contains(rx3) << 3;
// etc.
switch(mask) {
case 1: ...
case 2: ...
case 4: ...
};
Just be aware this code is suboptimal - every regular expression has to be evaluated. With a bunch of if statements only those are evaluated that are before the one that matches.

If you are worried about your code looking like spaghetti, you can simplify the syntax with macro expansion.

jdiewald
2nd March 2011, 22:36
mask |= line.contains(rx1) << 1;
mask |= line.contains(rx2) << 2;
mask |= line.contains(rx3) << 3;
// etc.
switch(mask) {
case 1: ...
case 2: ...
case 4: ...
};

If you use this structure, you should also add a default clause to the switch, with an assertion failure or exception. This will protect you against the inevitable day when something in the code changes and more than one of the regular expressions succeeds.

nightghost
2nd March 2011, 23:26
If you use this structure, you should also add a default clause to the switch, with an assertion failure or exception. This will protect you against the inevitable day when something in the code changes and more than one of the regular expressions succeeds.

He's reading the data from a (external) file. Adding assertions/exceptions can be quite dangerous. The programm should not crash every time the file is messed up.

MarekR22
3rd March 2011, 10:37
Can you be more specific what you are parsing?
I'm quite sure that this issue can be solved in better way.
One of possibilities is union of regular expretions:

QRegExp regExp("(regExp1)|(regExp2)|(regExp3)|(regExp4)")

while(1) // this (!in.EOF) was wrong!
{
line = in.readLine();
if (line.isNull()) {
break;
}
if(line.contains(regExp)){
const QStringList result = regExp.capturedTexts();
int i;
for (i=0; i<result.count(); ++i) {
if (!result[i].isEmpty()) {
break; // or some action to take
}
}
// process i value
}
}

nightghost
3rd March 2011, 12:44
@MarekR22: Could you explain why a while(1) should be better than a check of the end of the buffer/file/whatever?

But another idea:



// base class
struct Matcher {
virtual bool matches(line);
virtual void doStuff();
}

// impl
struct Matcher1 : public Matcher {...}
struct Matcher2 : public Matcher {...}

// algorithm
// 1.) make a list of the matcher

foreach(const QString& line, lines) {

foreach(Matcher* matcher, list_of_matchers) {

if(matcher->matches(line)) {
matcher->doStuff();
break;
}
}

}

MarekR22
3rd March 2011, 14:32
this is more like STL habit where this kind construction is obligatory since in STL istream::eof() returns true only when attempt of reading bound end of file happened.
In Qt you there is no EOF method, but method QTextStream::atEnd and this is why I confused things (sorry). This different names indicates that it works in different way.